mirror of
https://github.com/LCEMP/LCEMP.git
synced 2026-05-14 09:37:34 +00:00
LCEMP v1.1.0, bugfixes, multithreading server, local leaderboard, performance fixes, and more
This commit is contained in:
parent
fadeee4192
commit
7e7668c7fa
|
|
@ -169,7 +169,7 @@ void Chunk::makeCopyForRebuild(Chunk *source)
|
|||
this->xm = source->xm;
|
||||
this->ym = source->ym;
|
||||
this->zm = source->zm;
|
||||
this->bb = source->bb;
|
||||
this->bb = NULL;
|
||||
this->clipChunk = NULL;
|
||||
this->id = source->id;
|
||||
this->globalRenderableTileEntities = source->globalRenderableTileEntities;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#define GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE 0x00010000
|
||||
#define GAME_HOST_OPTION_BITMASK_BEDROCKFOG 0x00020000
|
||||
#define GAME_HOST_OPTION_BITMASK_DISABLESAVE 0x00040000
|
||||
#define GAME_HOST_OPTION_BITMASK_CHATDISABLED 0x00080000
|
||||
#define GAME_HOST_OPTION_BITMASK_ALL 0xFFFFFFFF
|
||||
|
||||
#ifdef _XBOX
|
||||
|
|
|
|||
|
|
@ -622,6 +622,7 @@ enum eGameHostOption
|
|||
eGameHostOption_All,
|
||||
|
||||
eGameHostOption_DisableSaving,
|
||||
eGameHostOption_ChatDisabled,
|
||||
};
|
||||
|
||||
// 4J-PB - If any new DLC items are added to the TMSFiles, this array needs updated
|
||||
|
|
|
|||
|
|
@ -26,6 +26,30 @@ typedef struct
|
|||
}
|
||||
NOTIFICATION,*PNOTIFICATION;
|
||||
|
||||
static const unsigned char WIN64_SAVED_SERVER_FILE_VERSION = 1;
|
||||
static const int WIN64_SAVED_SERVER_MAX = 64;
|
||||
static const int WIN64_SAVED_SERVER_NAME_CHARS = 20;
|
||||
static const int WIN64_SAVED_SERVER_HOST_CHARS = 64;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szName[WIN64_SAVED_SERVER_NAME_CHARS];
|
||||
char szHost[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
unsigned short usPort;
|
||||
unsigned char ucInUse;
|
||||
unsigned char ucReserved;
|
||||
}
|
||||
WIN64_SAVED_SERVER_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char ucVersion;
|
||||
unsigned char ucCount;
|
||||
unsigned short usReserved;
|
||||
WIN64_SAVED_SERVER_ENTRY entries[WIN64_SAVED_SERVER_MAX];
|
||||
}
|
||||
WIN64_SAVED_SERVER_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool bSettingsChanged;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../Minecraft.World/Recipy.h"
|
||||
#include "../../Minecraft.Client/Options.h"
|
||||
#include "../../Minecraft.World/AABB.h"
|
||||
|
|
@ -1628,6 +1630,696 @@ unsigned char CMinecraftApp::GetMinecraftLanguage(int iPad)
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined(_WINDOWS64)
|
||||
static const unsigned short kSavedServerDefaultPort = 25565;
|
||||
static const unsigned char kLegacySavedServerProfileVersion = 1;
|
||||
static const int kLegacySavedServerMax = 3;
|
||||
static const int kLegacySavedServerNameChars = 20;
|
||||
static const int kLegacySavedServerHostChars = 32;
|
||||
static const char kSavedServerFileMagic[4] = { 'S', 'R', 'V', '1' };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szName[kLegacySavedServerNameChars];
|
||||
char szHost[kLegacySavedServerHostChars];
|
||||
unsigned short usPort;
|
||||
unsigned char ucInUse;
|
||||
unsigned char ucReserved;
|
||||
}
|
||||
WIN64_LEGACY_SAVED_SERVER_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char ucVersion;
|
||||
unsigned char ucCount;
|
||||
unsigned short usReserved;
|
||||
WIN64_LEGACY_SAVED_SERVER_ENTRY entries[kLegacySavedServerMax];
|
||||
}
|
||||
WIN64_LEGACY_SAVED_SERVER_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szMagic[4];
|
||||
WIN64_SAVED_SERVER_DATA data;
|
||||
}
|
||||
WIN64_SAVED_SERVER_FILE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool bLoaded;
|
||||
char szFilePath[MAX_PATH];
|
||||
WIN64_SAVED_SERVER_DATA data;
|
||||
}
|
||||
WIN64_SAVED_SERVER_CACHE_ENTRY;
|
||||
|
||||
static WIN64_SAVED_SERVER_CACHE_ENTRY g_savedServerCacheA[XUSER_MAX_COUNT];
|
||||
|
||||
static bool IsDigitsOnly(const char *text)
|
||||
{
|
||||
if (text == NULL || text[0] == 0)
|
||||
return false;
|
||||
|
||||
for (const char *it = text; *it != 0; ++it)
|
||||
{
|
||||
if (*it < '0' || *it > '9')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsValidIPv4Address(const char *host)
|
||||
{
|
||||
if (host == NULL || host[0] == 0)
|
||||
return false;
|
||||
|
||||
int octetCount = 0;
|
||||
const char *segmentStart = host;
|
||||
for (const char *it = host;; ++it)
|
||||
{
|
||||
if (*it == '.' || *it == 0)
|
||||
{
|
||||
char segment[8];
|
||||
int segLen = (int)(it - segmentStart);
|
||||
if (segLen <= 0 || segLen >= (int)sizeof(segment))
|
||||
return false;
|
||||
|
||||
memcpy(segment, segmentStart, segLen);
|
||||
segment[segLen] = 0;
|
||||
if (!IsDigitsOnly(segment))
|
||||
return false;
|
||||
|
||||
int value = atoi(segment);
|
||||
if (value < 0 || value > 255)
|
||||
return false;
|
||||
|
||||
++octetCount;
|
||||
if (*it == 0)
|
||||
break;
|
||||
|
||||
segmentStart = it + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (octetCount == 4);
|
||||
}
|
||||
|
||||
static bool IsReasonableSavedServerHost(const char *host)
|
||||
{
|
||||
if (host == NULL || host[0] == 0)
|
||||
return false;
|
||||
|
||||
if (_stricmp(host, "localhost") == 0)
|
||||
return true;
|
||||
|
||||
if (IsValidIPv4Address(host))
|
||||
return true;
|
||||
|
||||
bool hasDot = false;
|
||||
int labelLen = 0;
|
||||
char prev = 0;
|
||||
for (const char *it = host; *it != 0; ++it)
|
||||
{
|
||||
char c = *it;
|
||||
bool isAlphaNum = ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'));
|
||||
|
||||
if (c == '.')
|
||||
{
|
||||
if (labelLen == 0 || prev == '-')
|
||||
return false;
|
||||
hasDot = true;
|
||||
labelLen = 0;
|
||||
}
|
||||
else if (isAlphaNum || c == '-')
|
||||
{
|
||||
if (labelLen == 0 && c == '-')
|
||||
return false;
|
||||
|
||||
++labelLen;
|
||||
if (labelLen > 63)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
prev = c;
|
||||
}
|
||||
|
||||
if (labelLen == 0 || prev == '-')
|
||||
return false;
|
||||
|
||||
return hasDot;
|
||||
}
|
||||
|
||||
static void InitSavedServerData(WIN64_SAVED_SERVER_DATA *data)
|
||||
{
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
ZeroMemory(data, sizeof(*data));
|
||||
data->ucVersion = WIN64_SAVED_SERVER_FILE_VERSION;
|
||||
data->ucCount = 0;
|
||||
}
|
||||
|
||||
static bool NormalizeSavedServerData(WIN64_SAVED_SERVER_DATA *data)
|
||||
{
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
bool normalized = false;
|
||||
unsigned char originalCount = data->ucCount;
|
||||
if (data->ucVersion != WIN64_SAVED_SERVER_FILE_VERSION || data->ucCount > WIN64_SAVED_SERVER_MAX)
|
||||
{
|
||||
InitSavedServerData(data);
|
||||
normalized = true;
|
||||
}
|
||||
|
||||
int compactedCount = 0;
|
||||
for (int i = 0; i < WIN64_SAVED_SERVER_MAX; ++i)
|
||||
{
|
||||
WIN64_SAVED_SERVER_ENTRY originalEntry = data->entries[i];
|
||||
WIN64_SAVED_SERVER_ENTRY entry = originalEntry;
|
||||
entry.szName[WIN64_SAVED_SERVER_NAME_CHARS - 1] = 0;
|
||||
entry.szHost[WIN64_SAVED_SERVER_HOST_CHARS - 1] = 0;
|
||||
|
||||
if (entry.ucInUse == 0 || entry.szHost[0] == 0)
|
||||
continue;
|
||||
|
||||
if (!IsReasonableSavedServerHost(entry.szHost))
|
||||
{
|
||||
normalized = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.usPort == 0)
|
||||
{
|
||||
entry.usPort = kSavedServerDefaultPort;
|
||||
normalized = true;
|
||||
}
|
||||
|
||||
if (entry.szName[0] == 0)
|
||||
{
|
||||
strncpy_s(entry.szName, WIN64_SAVED_SERVER_NAME_CHARS, entry.szHost, _TRUNCATE);
|
||||
normalized = true;
|
||||
}
|
||||
|
||||
entry.ucInUse = 1;
|
||||
entry.ucReserved = 0;
|
||||
|
||||
bool duplicate = false;
|
||||
for (int j = 0; j < compactedCount; ++j)
|
||||
{
|
||||
if (_stricmp(data->entries[j].szHost, entry.szHost) == 0 && data->entries[j].usPort == entry.usPort)
|
||||
{
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicate)
|
||||
{
|
||||
normalized = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i != compactedCount)
|
||||
normalized = true;
|
||||
|
||||
if (memcmp(&originalEntry, &entry, sizeof(entry)) != 0)
|
||||
normalized = true;
|
||||
|
||||
data->entries[compactedCount++] = entry;
|
||||
}
|
||||
|
||||
for (int i = compactedCount; i < WIN64_SAVED_SERVER_MAX; ++i)
|
||||
{
|
||||
if (data->entries[i].ucInUse != 0 || data->entries[i].szHost[0] != 0 || data->entries[i].szName[0] != 0 || data->entries[i].usPort != 0)
|
||||
normalized = true;
|
||||
ZeroMemory(&data->entries[i], sizeof(data->entries[i]));
|
||||
}
|
||||
|
||||
data->ucCount = (unsigned char)compactedCount;
|
||||
if (data->ucCount != originalCount)
|
||||
normalized = true;
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
static void CopyTrimmedAscii(char *out, int outSize, const char *in)
|
||||
{
|
||||
if (out == NULL || outSize <= 0)
|
||||
return;
|
||||
|
||||
out[0] = 0;
|
||||
if (in == NULL)
|
||||
return;
|
||||
|
||||
const char *start = in;
|
||||
while (*start == ' ' || *start == '\t' || *start == '\r' || *start == '\n')
|
||||
++start;
|
||||
|
||||
const char *end = start + strlen(start);
|
||||
while (end > start)
|
||||
{
|
||||
char ch = *(end - 1);
|
||||
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
|
||||
--end;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int len = (int)(end - start);
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
if (len >= outSize)
|
||||
len = outSize - 1;
|
||||
|
||||
memcpy(out, start, len);
|
||||
out[len] = 0;
|
||||
}
|
||||
|
||||
static bool BuildSavedServerFilePath(int iPad, char *outPath, int outPathSize)
|
||||
{
|
||||
if (outPath == NULL || outPathSize <= 0)
|
||||
return false;
|
||||
|
||||
char dirPath[MAX_PATH];
|
||||
#if defined(__linux__)
|
||||
const char *baseDir = getenv("XDG_DATA_HOME");
|
||||
if (baseDir != NULL && baseDir[0] != 0)
|
||||
{
|
||||
int written = snprintf(dirPath, MAX_PATH, "%s/minecraft", baseDir);
|
||||
if (written <= 0 || written >= MAX_PATH)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
baseDir = getenv("HOME");
|
||||
if (baseDir == NULL || baseDir[0] == 0)
|
||||
return false;
|
||||
|
||||
int written = snprintf(dirPath, MAX_PATH, "%s/.minecraft", baseDir);
|
||||
if (written <= 0 || written >= MAX_PATH)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
const char *baseDir = getenv("APPDATA");
|
||||
if (baseDir == NULL || baseDir[0] == 0)
|
||||
return false;
|
||||
|
||||
int written = _snprintf_s(dirPath, MAX_PATH, _TRUNCATE, "%s\\Minecraft", baseDir);
|
||||
if (written <= 0 || written >= MAX_PATH)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
CreateDirectoryA(dirPath, NULL);
|
||||
|
||||
PlayerUID profileXuid = INVALID_XUID;
|
||||
if (iPad >= 0 && iPad < XUSER_MAX_COUNT)
|
||||
{
|
||||
ProfileManager.GetXUID(iPad, &profileXuid, false);
|
||||
if (profileXuid == INVALID_XUID)
|
||||
{
|
||||
ProfileManager.GetXUID(iPad, &profileXuid, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (profileXuid != INVALID_XUID)
|
||||
{
|
||||
unsigned __int64 xuidVal = (unsigned __int64)profileXuid;
|
||||
#if defined(__linux__)
|
||||
int written = snprintf(outPath, outPathSize, "%s/saved_servers_%016llX.dat", dirPath, (unsigned long long)xuidVal);
|
||||
#else
|
||||
int written = _snprintf_s(outPath, outPathSize, _TRUNCATE, "%s\\saved_servers_%016llX.dat", dirPath, (unsigned long long)xuidVal);
|
||||
#endif
|
||||
if (written <= 0 || written >= outPathSize)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int safePad = (iPad >= 0 && iPad < XUSER_MAX_COUNT) ? iPad : 0;
|
||||
#if defined(__linux__)
|
||||
int written = snprintf(outPath, outPathSize, "%s/saved_servers_pad%d.dat", dirPath, safePad);
|
||||
#else
|
||||
int written = _snprintf_s(outPath, outPathSize, _TRUNCATE, "%s\\saved_servers_pad%d.dat", dirPath, safePad);
|
||||
#endif
|
||||
if (written <= 0 || written >= outPathSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadSavedServerFile(const char *path, WIN64_SAVED_SERVER_DATA *outData)
|
||||
{
|
||||
if (path == NULL || path[0] == 0 || outData == NULL)
|
||||
return false;
|
||||
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (file == NULL)
|
||||
return false;
|
||||
|
||||
WIN64_SAVED_SERVER_FILE diskData;
|
||||
ZeroMemory(&diskData, sizeof(diskData));
|
||||
|
||||
size_t bytesRead = fread(&diskData, 1, sizeof(diskData), file);
|
||||
fclose(file);
|
||||
|
||||
if (bytesRead != sizeof(diskData))
|
||||
return false;
|
||||
|
||||
if (memcmp(diskData.szMagic, kSavedServerFileMagic, sizeof(kSavedServerFileMagic)) != 0)
|
||||
return false;
|
||||
|
||||
*outData = diskData.data;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SaveSavedServerFile(const char *path, const WIN64_SAVED_SERVER_DATA *data)
|
||||
{
|
||||
if (path == NULL || path[0] == 0 || data == NULL)
|
||||
return false;
|
||||
|
||||
WIN64_SAVED_SERVER_FILE diskData;
|
||||
ZeroMemory(&diskData, sizeof(diskData));
|
||||
memcpy(diskData.szMagic, kSavedServerFileMagic, sizeof(kSavedServerFileMagic));
|
||||
diskData.data = *data;
|
||||
|
||||
FILE *file = fopen(path, "wb");
|
||||
if (file == NULL)
|
||||
return false;
|
||||
|
||||
size_t bytesWritten = fwrite(&diskData, 1, sizeof(diskData), file);
|
||||
fclose(file);
|
||||
|
||||
return bytesWritten == sizeof(diskData);
|
||||
}
|
||||
|
||||
static bool TryImportLegacySavedServers(const GAME_SETTINGS *settings, WIN64_SAVED_SERVER_DATA *data)
|
||||
{
|
||||
if (settings == NULL || data == NULL)
|
||||
return false;
|
||||
|
||||
const WIN64_LEGACY_SAVED_SERVER_DATA *legacyData = (const WIN64_LEGACY_SAVED_SERVER_DATA *)&settings->ucTutorialCompletion[0];
|
||||
if (legacyData->ucVersion != kLegacySavedServerProfileVersion || legacyData->ucCount > kLegacySavedServerMax)
|
||||
return false;
|
||||
|
||||
int importedCount = 0;
|
||||
for (int i = 0; i < kLegacySavedServerMax && importedCount < WIN64_SAVED_SERVER_MAX; ++i)
|
||||
{
|
||||
WIN64_LEGACY_SAVED_SERVER_ENTRY entry = legacyData->entries[i];
|
||||
entry.szName[kLegacySavedServerNameChars - 1] = 0;
|
||||
entry.szHost[kLegacySavedServerHostChars - 1] = 0;
|
||||
|
||||
if (entry.ucInUse == 0 || entry.szHost[0] == 0)
|
||||
continue;
|
||||
|
||||
if (!IsReasonableSavedServerHost(entry.szHost))
|
||||
continue;
|
||||
|
||||
WIN64_SAVED_SERVER_ENTRY imported;
|
||||
ZeroMemory(&imported, sizeof(imported));
|
||||
strncpy_s(imported.szHost, WIN64_SAVED_SERVER_HOST_CHARS, entry.szHost, _TRUNCATE);
|
||||
if (entry.szName[0] != 0)
|
||||
strncpy_s(imported.szName, WIN64_SAVED_SERVER_NAME_CHARS, entry.szName, _TRUNCATE);
|
||||
else
|
||||
strncpy_s(imported.szName, WIN64_SAVED_SERVER_NAME_CHARS, imported.szHost, _TRUNCATE);
|
||||
|
||||
imported.usPort = (entry.usPort == 0) ? kSavedServerDefaultPort : entry.usPort;
|
||||
imported.ucInUse = 1;
|
||||
imported.ucReserved = 0;
|
||||
|
||||
data->entries[importedCount++] = imported;
|
||||
}
|
||||
|
||||
if (importedCount <= 0)
|
||||
return false;
|
||||
|
||||
data->ucCount = (unsigned char)importedCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
static WIN64_SAVED_SERVER_DATA *GetSavedServerData(int iPad, GAME_SETTINGS *settings)
|
||||
{
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return NULL;
|
||||
|
||||
WIN64_SAVED_SERVER_CACHE_ENTRY *cache = &g_savedServerCacheA[iPad];
|
||||
|
||||
char filePath[MAX_PATH];
|
||||
if (!BuildSavedServerFilePath(iPad, filePath, MAX_PATH))
|
||||
return NULL;
|
||||
|
||||
if (!cache->bLoaded || _stricmp(cache->szFilePath, filePath) != 0)
|
||||
{
|
||||
bool loadedFromDisk = LoadSavedServerFile(filePath, &cache->data);
|
||||
if (!loadedFromDisk)
|
||||
{
|
||||
InitSavedServerData(&cache->data);
|
||||
}
|
||||
|
||||
bool changed = NormalizeSavedServerData(&cache->data);
|
||||
|
||||
if (!loadedFromDisk)
|
||||
{
|
||||
WIN64_SAVED_SERVER_DATA migratedData;
|
||||
InitSavedServerData(&migratedData);
|
||||
if (TryImportLegacySavedServers(settings, &migratedData))
|
||||
{
|
||||
cache->data = migratedData;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy_s(cache->szFilePath, MAX_PATH, filePath, _TRUNCATE);
|
||||
cache->bLoaded = true;
|
||||
|
||||
if (changed || !loadedFromDisk)
|
||||
{
|
||||
SaveSavedServerFile(cache->szFilePath, &cache->data);
|
||||
}
|
||||
}
|
||||
|
||||
return &cache->data;
|
||||
}
|
||||
|
||||
static bool SaveSavedServerData(int iPad)
|
||||
{
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return false;
|
||||
|
||||
WIN64_SAVED_SERVER_CACHE_ENTRY *cache = &g_savedServerCacheA[iPad];
|
||||
if (!cache->bLoaded || cache->szFilePath[0] == 0)
|
||||
return false;
|
||||
|
||||
return SaveSavedServerFile(cache->szFilePath, &cache->data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int CMinecraftApp::GetSavedServerCount(int iPad)
|
||||
{
|
||||
#if defined(_WINDOWS64)
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return 0;
|
||||
|
||||
GAME_SETTINGS *settings = GameSettingsA[iPad];
|
||||
WIN64_SAVED_SERVER_DATA *data = GetSavedServerData(iPad, settings);
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
|
||||
return (int)data->ucCount;
|
||||
#else
|
||||
(void)iPad;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CMinecraftApp::GetSavedServer(int iPad, int index, char *pName, int nameSize, char *pHost, int hostSize, unsigned short *pPort)
|
||||
{
|
||||
#if defined(_WINDOWS64)
|
||||
if (pName != NULL && nameSize > 0)
|
||||
pName[0] = 0;
|
||||
if (pHost != NULL && hostSize > 0)
|
||||
pHost[0] = 0;
|
||||
if (pPort != NULL)
|
||||
*pPort = 0;
|
||||
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return false;
|
||||
|
||||
GAME_SETTINGS *settings = GameSettingsA[iPad];
|
||||
WIN64_SAVED_SERVER_DATA *data = GetSavedServerData(iPad, settings);
|
||||
if (data == NULL || index < 0 || index >= (int)data->ucCount)
|
||||
return false;
|
||||
|
||||
WIN64_SAVED_SERVER_ENTRY *entry = &data->entries[index];
|
||||
if (entry->ucInUse == 0 || entry->szHost[0] == 0)
|
||||
return false;
|
||||
|
||||
if (pName != NULL && nameSize > 0)
|
||||
strncpy_s(pName, nameSize, entry->szName, _TRUNCATE);
|
||||
if (pHost != NULL && hostSize > 0)
|
||||
strncpy_s(pHost, hostSize, entry->szHost, _TRUNCATE);
|
||||
if (pPort != NULL)
|
||||
*pPort = entry->usPort;
|
||||
|
||||
return true;
|
||||
#else
|
||||
(void)iPad;
|
||||
(void)index;
|
||||
(void)pName;
|
||||
(void)nameSize;
|
||||
(void)pHost;
|
||||
(void)hostSize;
|
||||
(void)pPort;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CMinecraftApp::AddOrUpdateSavedServer(int iPad, const char *pszName, const char *pszHost, unsigned short usPort)
|
||||
{
|
||||
#if defined(_WINDOWS64)
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return false;
|
||||
|
||||
GAME_SETTINGS *settings = GameSettingsA[iPad];
|
||||
WIN64_SAVED_SERVER_DATA *data = GetSavedServerData(iPad, settings);
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
char host[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
CopyTrimmedAscii(host, WIN64_SAVED_SERVER_HOST_CHARS, pszHost);
|
||||
if (host[0] == 0)
|
||||
return false;
|
||||
|
||||
if (!IsReasonableSavedServerHost(host))
|
||||
return false;
|
||||
|
||||
char name[WIN64_SAVED_SERVER_NAME_CHARS];
|
||||
CopyTrimmedAscii(name, WIN64_SAVED_SERVER_NAME_CHARS, pszName);
|
||||
if (name[0] == 0)
|
||||
strncpy_s(name, WIN64_SAVED_SERVER_NAME_CHARS, host, _TRUNCATE);
|
||||
|
||||
if (usPort == 0)
|
||||
usPort = kSavedServerDefaultPort;
|
||||
|
||||
WIN64_SAVED_SERVER_ENTRY newEntry;
|
||||
ZeroMemory(&newEntry, sizeof(newEntry));
|
||||
strncpy_s(newEntry.szName, WIN64_SAVED_SERVER_NAME_CHARS, name, _TRUNCATE);
|
||||
strncpy_s(newEntry.szHost, WIN64_SAVED_SERVER_HOST_CHARS, host, _TRUNCATE);
|
||||
newEntry.usPort = usPort;
|
||||
newEntry.ucInUse = 1;
|
||||
|
||||
int existingIndex = -1;
|
||||
for (int i = 0; i < (int)data->ucCount; ++i)
|
||||
{
|
||||
if (_stricmp(data->entries[i].szHost, host) == 0 && data->entries[i].usPort == usPort)
|
||||
{
|
||||
existingIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingIndex >= 0)
|
||||
{
|
||||
for (int i = existingIndex; i > 0; --i)
|
||||
{
|
||||
data->entries[i] = data->entries[i - 1];
|
||||
}
|
||||
data->entries[0] = newEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
int newCount = (int)data->ucCount;
|
||||
if (newCount < WIN64_SAVED_SERVER_MAX)
|
||||
++newCount;
|
||||
|
||||
for (int i = newCount - 1; i > 0; --i)
|
||||
{
|
||||
data->entries[i] = data->entries[i - 1];
|
||||
}
|
||||
data->entries[0] = newEntry;
|
||||
data->ucCount = (unsigned char)newCount;
|
||||
}
|
||||
|
||||
NormalizeSavedServerData(data);
|
||||
return SaveSavedServerData(iPad);
|
||||
#else
|
||||
(void)iPad;
|
||||
(void)pszName;
|
||||
(void)pszHost;
|
||||
(void)usPort;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CMinecraftApp::RemoveSavedServer(int iPad, const char *pszHost, unsigned short usPort)
|
||||
{
|
||||
#if defined(_WINDOWS64)
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
return false;
|
||||
|
||||
GAME_SETTINGS *settings = GameSettingsA[iPad];
|
||||
WIN64_SAVED_SERVER_DATA *data = GetSavedServerData(iPad, settings);
|
||||
if (data == NULL || data->ucCount == 0)
|
||||
return false;
|
||||
|
||||
char host[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
CopyTrimmedAscii(host, WIN64_SAVED_SERVER_HOST_CHARS, pszHost);
|
||||
if (host[0] == 0)
|
||||
return false;
|
||||
|
||||
if (usPort == 0)
|
||||
usPort = kSavedServerDefaultPort;
|
||||
|
||||
int removeIndex = -1;
|
||||
for (int i = 0; i < (int)data->ucCount; ++i)
|
||||
{
|
||||
if (_stricmp(data->entries[i].szHost, host) == 0 && data->entries[i].usPort == usPort)
|
||||
{
|
||||
removeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removeIndex < 0)
|
||||
return false;
|
||||
|
||||
for (int i = removeIndex; i < (int)data->ucCount - 1; ++i)
|
||||
{
|
||||
data->entries[i] = data->entries[i + 1];
|
||||
}
|
||||
|
||||
if (data->ucCount > 0)
|
||||
{
|
||||
--data->ucCount;
|
||||
ZeroMemory(&data->entries[data->ucCount], sizeof(data->entries[data->ucCount]));
|
||||
}
|
||||
|
||||
NormalizeSavedServerData(data);
|
||||
return SaveSavedServerData(iPad);
|
||||
#else
|
||||
(void)iPad;
|
||||
(void)pszHost;
|
||||
(void)usPort;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CMinecraftApp::SetGameSettings(int iPad,eGameSetting eVal,unsigned char ucVal)
|
||||
{
|
||||
//Minecraft *pMinecraft=Minecraft::GetInstance();
|
||||
|
|
@ -2717,7 +3409,7 @@ void CMinecraftApp::HandleXuiActions(void)
|
|||
int iPlayerC=g_NetworkManager.GetPlayerCount();
|
||||
|
||||
// Since the player is exiting, let's flush any profile writes for them, and hope we're not breaking TCR 136...
|
||||
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
|
||||
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
|
||||
StorageManager.ForceQueuedProfileWrites(i);
|
||||
LeaderboardManager::Instance()->OpenSession();
|
||||
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
||||
|
|
@ -2729,9 +3421,21 @@ void CMinecraftApp::HandleXuiActions(void)
|
|||
}
|
||||
}
|
||||
LeaderboardManager::Instance()->CloseSession();
|
||||
#else
|
||||
#elif (defined _WINDOWS64)
|
||||
ProfileManager.ForceQueuedProfileWrites(i);
|
||||
#endif
|
||||
LeaderboardManager::Instance()->OpenSession();
|
||||
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
||||
{
|
||||
if( ProfileManager.IsSignedIn(j) )
|
||||
{
|
||||
app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
|
||||
Minecraft::GetInstance()->forceStatsSave(j);
|
||||
}
|
||||
}
|
||||
LeaderboardManager::Instance()->CloseSession();
|
||||
#else
|
||||
ProfileManager.ForceQueuedProfileWrites(i);
|
||||
#endif
|
||||
|
||||
// not required - it's done within the removeLocalPlayerIdx
|
||||
// if(pMinecraft->level->isClientSide)
|
||||
|
|
@ -2950,21 +3654,33 @@ void CMinecraftApp::HandleXuiActions(void)
|
|||
ui.HideAllGameUIElements();
|
||||
|
||||
// Since the player forced the exit, let's flush any profile writes, and hope we're not breaking TCR 136...
|
||||
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
|
||||
StorageManager.ForceQueuedProfileWrites();
|
||||
LeaderboardManager::Instance()->OpenSession();
|
||||
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
||||
{
|
||||
if( ProfileManager.IsSignedIn(j) )
|
||||
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__)
|
||||
StorageManager.ForceQueuedProfileWrites();
|
||||
LeaderboardManager::Instance()->OpenSession();
|
||||
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
||||
{
|
||||
app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
|
||||
Minecraft::GetInstance()->forceStatsSave(j);
|
||||
if( ProfileManager.IsSignedIn(j) )
|
||||
{
|
||||
app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
|
||||
Minecraft::GetInstance()->forceStatsSave(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
LeaderboardManager::Instance()->CloseSession();
|
||||
#elif (defined _XBOX)
|
||||
ProfileManager.ForceQueuedProfileWrites();
|
||||
#endif
|
||||
LeaderboardManager::Instance()->CloseSession();
|
||||
#elif (defined _XBOX)
|
||||
ProfileManager.ForceQueuedProfileWrites();
|
||||
#elif (defined _WINDOWS64)
|
||||
ProfileManager.ForceQueuedProfileWrites();
|
||||
LeaderboardManager::Instance()->OpenSession();
|
||||
for (int j = 0; j < XUSER_MAX_COUNT; j++)
|
||||
{
|
||||
if( ProfileManager.IsSignedIn(j) )
|
||||
{
|
||||
app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0);
|
||||
Minecraft::GetInstance()->forceStatsSave(j);
|
||||
}
|
||||
}
|
||||
LeaderboardManager::Instance()->CloseSession();
|
||||
#endif
|
||||
|
||||
// 4J-PB - cancel any possible string verifications queued with LIVE
|
||||
//InputManager.CancelAllVerifyInProgress();
|
||||
|
|
@ -7612,6 +8328,17 @@ void CMinecraftApp::SetGameHostOption(unsigned int &uiHostSettings, eGameHostOpt
|
|||
uiHostSettings&=~GAME_HOST_OPTION_BITMASK_DISABLESAVE;
|
||||
}
|
||||
break;
|
||||
case eGameHostOption_ChatDisabled:
|
||||
if(uiVal!=0)
|
||||
{
|
||||
uiHostSettings|=GAME_HOST_OPTION_BITMASK_CHATDISABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// off
|
||||
uiHostSettings&=~GAME_HOST_OPTION_BITMASK_CHATDISABLED;
|
||||
}
|
||||
break;
|
||||
case eGameHostOption_All:
|
||||
uiHostSettings=uiVal;
|
||||
break;
|
||||
|
|
@ -7689,6 +8416,9 @@ unsigned int CMinecraftApp::GetGameHostOption(unsigned int uiHostSettings, eGame
|
|||
case eGameHostOption_DisableSaving:
|
||||
return (uiHostSettings&GAME_HOST_OPTION_BITMASK_DISABLESAVE);
|
||||
break;
|
||||
case eGameHostOption_ChatDisabled:
|
||||
return (uiHostSettings&GAME_HOST_OPTION_BITMASK_CHATDISABLED);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -247,6 +247,10 @@ public:
|
|||
// Minecraft language select
|
||||
void SetMinecraftLanguage(int iPad, unsigned char ucLanguage);
|
||||
unsigned char GetMinecraftLanguage(int iPad);
|
||||
int GetSavedServerCount(int iPad);
|
||||
bool GetSavedServer(int iPad, int index, char *pName, int nameSize, char *pHost, int hostSize, unsigned short *pPort);
|
||||
bool AddOrUpdateSavedServer(int iPad, const char *pszName, const char *pszHost, unsigned short usPort);
|
||||
bool RemoveSavedServer(int iPad, const char *pszHost, unsigned short usPort);
|
||||
|
||||
|
||||
// 4J-PB - set a timer when the user navigates the quickselect, so we can bring the opacity back to defaults for a short time
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "Common/UI/UI.h"
|
||||
#include "Common/UI/UIScene_PauseMenu.h"
|
||||
#include "../../Xbox/Network/NetworkPlayerXbox.h"
|
||||
#include "PlatformNetworkManagerStub.h"
|
||||
#endif
|
||||
|
||||
#ifdef _DURANGO
|
||||
|
|
@ -84,6 +85,9 @@ void CGameNetworkManager::Terminate()
|
|||
if( m_bInitialised )
|
||||
{
|
||||
s_pPlatformNetworkManager->Terminate();
|
||||
delete s_pPlatformNetworkManager;
|
||||
s_pPlatformNetworkManager = NULL;
|
||||
m_bInitialised = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -680,6 +684,16 @@ void CGameNetworkManager::CancelJoinGame(LPVOID lpParam)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool CGameNetworkManager::IsJoinPending()
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
CPlatformNetworkManagerStub *stub = (CPlatformNetworkManagerStub *)s_pPlatformNetworkManager;
|
||||
return stub->IsJoinPending();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CGameNetworkManager::LeaveGame(bool bMigrateHost)
|
||||
{
|
||||
Minecraft::GetInstance()->gui->clearMessages();
|
||||
|
|
@ -883,7 +897,11 @@ int CGameNetworkManager::ServerThreadProc( void* lpParameter )
|
|||
IntCache::ReleaseThreadStorage();
|
||||
Level::destroyLightingCache();
|
||||
|
||||
if(lpParameter != NULL) delete lpParameter;
|
||||
if (lpParameter != NULL)
|
||||
{
|
||||
NetworkGameInitData *param = (NetworkGameInitData *)lpParameter;
|
||||
delete param;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ public:
|
|||
{
|
||||
JOINGAME_SUCCESS,
|
||||
JOINGAME_FAIL_GENERAL,
|
||||
JOINGAME_FAIL_SERVER_FULL
|
||||
JOINGAME_FAIL_SERVER_FULL,
|
||||
JOINGAME_PENDING
|
||||
} eJoinGameResult;
|
||||
|
||||
void Initialise();
|
||||
|
|
@ -103,7 +104,8 @@ public:
|
|||
// Session joining and leaving
|
||||
|
||||
bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo);
|
||||
eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask);
|
||||
eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask);
|
||||
bool IsJoinPending();
|
||||
static void CancelJoinGame(LPVOID lpParam); // Not part of the shared interface
|
||||
bool LeaveGame(bool bMigrateHost);
|
||||
static int JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
|
|||
m_pSearchParam = NULL;
|
||||
m_SessionsUpdatedCallback = NULL;
|
||||
|
||||
m_asyncJoinPending = false;
|
||||
|
||||
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
||||
{
|
||||
m_searchResultsCount[i] = 0;
|
||||
|
|
@ -196,6 +198,32 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
|
|||
|
||||
void CPlatformNetworkManagerStub::Terminate()
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
m_asyncJoinPending = false;
|
||||
WinsockNetLayer::CancelJoinGame();
|
||||
WinsockNetLayer::StopAdvertising();
|
||||
WinsockNetLayer::StopDiscovery();
|
||||
WinsockNetLayer::Shutdown();
|
||||
#endif
|
||||
|
||||
m_bLeavingGame = false;
|
||||
m_bLeaveGameOnTick = false;
|
||||
m_bHostChanged = false;
|
||||
|
||||
for (AUTO_VAR(it, currentNetworkPlayers.begin()); it != currentNetworkPlayers.end(); ++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
currentNetworkPlayers.clear();
|
||||
m_machineQNetPrimaryPlayers.clear();
|
||||
SystemFlagReset();
|
||||
|
||||
if (m_pIQNet != NULL)
|
||||
{
|
||||
m_pIQNet->EndGame();
|
||||
delete m_pIQNet;
|
||||
m_pIQNet = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CPlatformNetworkManagerStub::GetJoiningReadyPercentage()
|
||||
|
|
@ -218,6 +246,43 @@ void CPlatformNetworkManagerStub::DoWork()
|
|||
{
|
||||
#ifdef _WINDOWS64
|
||||
extern QNET_STATE _iQNetStubState;
|
||||
|
||||
if (m_asyncJoinPending)
|
||||
{
|
||||
WinsockNetLayer::JoinResult jr = WinsockNetLayer::PollJoinResult();
|
||||
if (jr == WinsockNetLayer::JOIN_SUCCESS)
|
||||
{
|
||||
m_asyncJoinPending = false;
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Async connect to %s:%d succeeded\n", m_asyncJoinIP, m_asyncJoinPort);
|
||||
}
|
||||
else if (jr == WinsockNetLayer::JOIN_FAILED)
|
||||
{
|
||||
m_asyncJoinPending = false;
|
||||
app.DebugPrintf("Win64 LAN: Async connect to %s:%d failed\n", m_asyncJoinIP, m_asyncJoinPort);
|
||||
WinsockNetLayer::CancelJoinGame();
|
||||
m_pIQNet->EndGame();
|
||||
extern bool g_connectedToDedicatedServer;
|
||||
g_connectedToDedicatedServer = false;
|
||||
m_pGameNetworkManager->StateChange_AnyToIdle();
|
||||
}
|
||||
}
|
||||
|
||||
if (_iQNetStubState == QNET_STATE_SESSION_STARTING && app.GetGameStarted())
|
||||
{
|
||||
_iQNetStubState = QNET_STATE_GAME_PLAY;
|
||||
|
|
@ -258,7 +323,8 @@ void CPlatformNetworkManagerStub::DoWork()
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
DWORD playerCapacity = IQNet::GetPlayerCapacity();
|
||||
for (DWORD i = 1; i < playerCapacity; i++)
|
||||
{
|
||||
IQNetPlayer *qp = &IQNet::m_player[i];
|
||||
if (qp->GetCustomDataValue() == 0)
|
||||
|
|
@ -418,7 +484,10 @@ void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame,
|
|||
_HostGame( localUsersMask, publicSlots, privateSlots );
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
int port = WIN64_NET_DEFAULT_PORT;
|
||||
extern int g_Win64MultiplayerPort;
|
||||
int port = g_Win64MultiplayerPort;
|
||||
if (port <= 0 || port > 65535)
|
||||
port = WIN64_NET_DEFAULT_PORT;
|
||||
if (!WinsockNetLayer::IsActive())
|
||||
WinsockNetLayer::HostGame(port);
|
||||
|
||||
|
|
@ -471,28 +540,23 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo *searchResult, int l
|
|||
|
||||
WinsockNetLayer::StopDiscovery();
|
||||
|
||||
if (!WinsockNetLayer::JoinGame(hostIP, hostPort))
|
||||
strncpy_s(m_asyncJoinIP, sizeof(m_asyncJoinIP), hostIP, _TRUNCATE);
|
||||
m_asyncJoinPort = hostPort;
|
||||
wcsncpy_s(m_asyncJoinHostName, 32, searchResult->data.hostName, _TRUNCATE);
|
||||
m_asyncJoinIsDedicated = searchResult->data.isDedicatedServer;
|
||||
|
||||
if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort))
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort);
|
||||
app.DebugPrintf("Win64 LAN: Failed to start async connect to %s:%d\n", hostIP, hostPort);
|
||||
WinsockNetLayer::CancelJoinGame();
|
||||
m_pIQNet->EndGame();
|
||||
g_connectedToDedicatedServer = false;
|
||||
m_pGameNetworkManager->StateChange_AnyToIdle();
|
||||
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;
|
||||
|
||||
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_asyncJoinPending = true;
|
||||
return CGameNetworkManager::JOINGAME_PENDING;
|
||||
#else
|
||||
return CGameNetworkManager::JOINGAME_SUCCESS;
|
||||
#endif
|
||||
|
|
@ -767,8 +831,7 @@ void CPlatformNetworkManagerStub::SearchForGames()
|
|||
bool alreadyPresent = false;
|
||||
for (size_t i = 0; i < lanSessions.size(); i++)
|
||||
{
|
||||
if (strcmp(lanSessions[i].hostIP, g_Win64MultiplayerIP) == 0 &&
|
||||
lanSessions[i].hostPort == g_Win64MultiplayerPort)
|
||||
if (_stricmp(lanSessions[i].hostIP, g_Win64MultiplayerIP) == 0 && lanSessions[i].hostPort == g_Win64MultiplayerPort)
|
||||
{
|
||||
alreadyPresent = true;
|
||||
break;
|
||||
|
|
@ -789,16 +852,82 @@ void CPlatformNetworkManagerStub::SearchForGames()
|
|||
}
|
||||
}
|
||||
|
||||
const int profilePad = ProfileManager.GetPrimaryPad();
|
||||
const int savedServerCount = app.GetSavedServerCount(profilePad);
|
||||
for (int i = 0; i < savedServerCount; ++i)
|
||||
{
|
||||
char savedName[WIN64_SAVED_SERVER_NAME_CHARS] = {0};
|
||||
char savedHost[WIN64_SAVED_SERVER_HOST_CHARS] = {0};
|
||||
unsigned short savedPort = WIN64_NET_DEFAULT_PORT;
|
||||
if (!app.GetSavedServer(profilePad, i, savedName, WIN64_SAVED_SERVER_NAME_CHARS, savedHost, WIN64_SAVED_SERVER_HOST_CHARS, &savedPort))
|
||||
continue;
|
||||
|
||||
if (savedHost[0] == '\0')
|
||||
continue;
|
||||
|
||||
if (savedPort == 0)
|
||||
savedPort = WIN64_NET_DEFAULT_PORT;
|
||||
|
||||
bool alreadyPresent = false;
|
||||
for (size_t n = 0; n < lanSessions.size(); ++n)
|
||||
{
|
||||
if (_stricmp(lanSessions[n].hostIP, savedHost) == 0 && lanSessions[n].hostPort == (int)savedPort)
|
||||
{
|
||||
alreadyPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyPresent)
|
||||
continue;
|
||||
|
||||
Win64LANSession saved;
|
||||
memset(&saved, 0, sizeof(saved));
|
||||
strncpy_s(saved.hostIP, sizeof(saved.hostIP), savedHost, _TRUNCATE);
|
||||
saved.hostPort = (int)savedPort;
|
||||
if (savedName[0] != '\0')
|
||||
{
|
||||
#if defined(__linux__) || !defined(_MSC_VER)
|
||||
size_t converted = mbstowcs(saved.hostName, savedName, 31);
|
||||
if (converted == (size_t)-1)
|
||||
saved.hostName[0] = L'\0';
|
||||
else
|
||||
saved.hostName[31] = L'\0';
|
||||
#else
|
||||
size_t converted = 0;
|
||||
mbstowcs_s(&converted, saved.hostName, 32, savedName, _TRUNCATE);
|
||||
#endif
|
||||
}
|
||||
if (saved.hostName[0] == L'\0')
|
||||
{
|
||||
swprintf_s(saved.hostName, 32, L"%hs:%d", savedHost, (int)savedPort);
|
||||
}
|
||||
saved.playerCount = 0;
|
||||
saved.maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
|
||||
saved.isJoinable = true;
|
||||
saved.isDedicatedServer = true;
|
||||
saved.lastSeenTick = GetTickCount();
|
||||
lanSessions.push_back(saved);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < friendsSessions[0].size(); i++)
|
||||
delete friendsSessions[0][i];
|
||||
friendsSessions[0].clear();
|
||||
|
||||
for (size_t i = 0; i < lanSessions.size(); i++)
|
||||
{
|
||||
wchar_t fallbackHostName[64];
|
||||
const wchar_t *resolvedHostName = lanSessions[i].hostName;
|
||||
if (resolvedHostName[0] == L'\0')
|
||||
{
|
||||
swprintf_s(fallbackHostName, 64, L"%hs:%d", lanSessions[i].hostIP, lanSessions[i].hostPort);
|
||||
resolvedHostName = fallbackHostName;
|
||||
}
|
||||
|
||||
FriendSessionInfo *info = new FriendSessionInfo();
|
||||
size_t nameLen = wcslen(lanSessions[i].hostName);
|
||||
size_t nameLen = wcslen(resolvedHostName);
|
||||
info->displayLabel = new wchar_t[nameLen + 1];
|
||||
wcscpy_s(info->displayLabel, nameLen + 1, lanSessions[i].hostName);
|
||||
wcscpy_s(info->displayLabel, nameLen + 1, resolvedHostName);
|
||||
info->displayLabelLength = (unsigned char)nameLen;
|
||||
info->displayLabelViewableStartIndex = 0;
|
||||
|
||||
|
|
@ -811,7 +940,7 @@ void CPlatformNetworkManagerStub::SearchForGames()
|
|||
info->data.isDedicatedServer = lanSessions[i].isDedicatedServer;
|
||||
strncpy_s(info->data.hostIP, sizeof(info->data.hostIP), lanSessions[i].hostIP, _TRUNCATE);
|
||||
info->data.hostPort = lanSessions[i].hostPort;
|
||||
wcsncpy_s(info->data.hostName, XUSER_NAME_SIZE, lanSessions[i].hostName, _TRUNCATE);
|
||||
wcsncpy_s(info->data.hostName, XUSER_NAME_SIZE, resolvedHostName, _TRUNCATE);
|
||||
info->data.playerCount = lanSessions[i].playerCount;
|
||||
info->data.maxPlayers = lanSessions[i].maxPlayers;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ public:
|
|||
virtual bool IsLeavingGame() { return m_bLeavingGame; }
|
||||
virtual void ResetLeavingGame() { m_bLeavingGame = false; }
|
||||
|
||||
bool IsJoinPending() { return m_asyncJoinPending; }
|
||||
|
||||
virtual void RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam);
|
||||
virtual void UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam);
|
||||
|
||||
|
|
@ -77,6 +79,12 @@ private:
|
|||
bool m_bIsPrivateGame;
|
||||
int m_flagIndexSize;
|
||||
|
||||
bool m_asyncJoinPending;
|
||||
char m_asyncJoinIP[64];
|
||||
int m_asyncJoinPort;
|
||||
wchar_t m_asyncJoinHostName[32];
|
||||
bool m_asyncJoinIsDedicated;
|
||||
|
||||
// This is only maintained by the host, and is not valid on client machines
|
||||
GameSessionData m_hostGameSessionData;
|
||||
CGameNetworkManager *m_pGameNetworkManager;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ void UIControl_LeaderboardList::setColumnIcon(int iColumn, int iType)
|
|||
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath(), m_funcSetColumnIcon , 2 , value );
|
||||
}
|
||||
|
||||
void UIControl_LeaderboardList::addDataSet(bool bLast, int iId, int iRank, const wstring &gamertag, bool bDisplayMessage, const wstring &col0, const wstring &col1, const wstring &col2, const wstring &col3, const wstring &col4, const wstring &col5, const wstring &col6)
|
||||
void UIControl_LeaderboardList::addDataSet(bool bLast, int iId, int iRank, const wstring &gamertag, const wstring &col0, const wstring &col1, const wstring &col2, const wstring &col3, const wstring &col4, const wstring &col5, const wstring &col6, bool bDisplayMessage)
|
||||
{
|
||||
IggyDataValue result;
|
||||
IggyDataValue value[12];
|
||||
|
|
@ -131,92 +131,92 @@ void UIControl_LeaderboardList::addDataSet(bool bLast, int iId, int iRank, const
|
|||
value[3].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[3].string16 = stringVal0;
|
||||
|
||||
value[4].type = IGGY_DATATYPE_boolean;
|
||||
value[4].boolval = bDisplayMessage;
|
||||
|
||||
IggyStringUTF16 stringVal1;
|
||||
stringVal1.string = (IggyUTF16*)col0.c_str();
|
||||
stringVal1.length = col0.length();
|
||||
value[5].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[5].string16 = stringVal1;
|
||||
value[4].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[4].string16 = stringVal1;
|
||||
|
||||
if(col1.empty())
|
||||
{
|
||||
value[6].type = IGGY_DATATYPE_null;
|
||||
value[5].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal2;
|
||||
stringVal2.string = (IggyUTF16*)col1.c_str();
|
||||
stringVal2.length = col1.length();
|
||||
value[6].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[6].string16 = stringVal2;
|
||||
value[5].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[5].string16 = stringVal2;
|
||||
}
|
||||
|
||||
if(col2.empty())
|
||||
{
|
||||
value[7].type = IGGY_DATATYPE_null;
|
||||
value[6].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal3;
|
||||
stringVal3.string = (IggyUTF16*)col2.c_str();
|
||||
stringVal3.length = col2.length();
|
||||
value[7].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[7].string16 = stringVal3;
|
||||
value[6].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[6].string16 = stringVal3;
|
||||
}
|
||||
|
||||
if(col3.empty())
|
||||
{
|
||||
value[8].type = IGGY_DATATYPE_null;
|
||||
value[7].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal4;
|
||||
stringVal4.string = (IggyUTF16*)col3.c_str();
|
||||
stringVal4.length = col3.length();
|
||||
value[8].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[8].string16 = stringVal4;
|
||||
value[7].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[7].string16 = stringVal4;
|
||||
}
|
||||
|
||||
if(col4.empty())
|
||||
{
|
||||
value[9].type = IGGY_DATATYPE_null;
|
||||
value[8].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal5;
|
||||
stringVal5.string = (IggyUTF16*)col4.c_str();
|
||||
stringVal5.length = col4.length();
|
||||
value[9].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[9].string16 = stringVal5;
|
||||
value[8].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[8].string16 = stringVal5;
|
||||
}
|
||||
|
||||
if(col5.empty())
|
||||
{
|
||||
value[10].type = IGGY_DATATYPE_null;
|
||||
value[9].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal6;
|
||||
stringVal6.string = (IggyUTF16*)col5.c_str();
|
||||
stringVal6.length = col5.length();
|
||||
value[10].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[10].string16 = stringVal6;
|
||||
value[9].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[9].string16 = stringVal6;
|
||||
}
|
||||
|
||||
if(col6.empty())
|
||||
{
|
||||
value[11].type = IGGY_DATATYPE_null;
|
||||
value[10].type = IGGY_DATATYPE_null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IggyStringUTF16 stringVal7;
|
||||
stringVal7.string = (IggyUTF16*)col6.c_str();
|
||||
stringVal7.length = col6.length();
|
||||
value[11].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[11].string16 = stringVal7;
|
||||
value[10].type = IGGY_DATATYPE_string_UTF16;
|
||||
value[10].string16 = stringVal7;
|
||||
}
|
||||
|
||||
value[11].type = IGGY_DATATYPE_boolean;
|
||||
value[11].boolval = bDisplayMessage;
|
||||
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath(), m_funcAddDataSet , 12 , value );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public:
|
|||
void setupTitles(const wstring &rank, const wstring &gamertag);
|
||||
void initLeaderboard(int iFirstFocus, int iTotalEntries, int iNumColumns);
|
||||
void setColumnIcon(int iColumn, int iType);
|
||||
void addDataSet(bool bLast, int iId, int iRank, const wstring &gamertag, bool bDisplayMessage, const wstring &col0, const wstring &col1, const wstring &col2, const wstring &col3, const wstring &col4, const wstring &col5, const wstring &col6);
|
||||
void addDataSet(bool bLast, int iId, int iRank, const wstring &gamertag, const wstring &col0, const wstring &col1, const wstring &col2, const wstring &col3, const wstring &col4, const wstring &col5, const wstring &col6, bool bDisplayMessage);
|
||||
|
||||
#ifdef __PSVITA__
|
||||
void SetTouchFocus(S32 iX, S32 iY, bool bRepeat);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#ifdef _WINDOWS64
|
||||
#include "../../KeyboardMouseInput.h"
|
||||
#include "UIControl_Slider.h"
|
||||
#include "UIScene_Keyboard.h"
|
||||
#endif
|
||||
#include "../../EnderDragonRenderer.h"
|
||||
#include "../../MultiPlayerLocalPlayer.h"
|
||||
|
|
@ -215,6 +216,7 @@ UIController::UIController()
|
|||
m_bCustomRenderPosition = false;
|
||||
m_winUserIndex = 0;
|
||||
m_accumulatedTicks = 0;
|
||||
m_windowsMouseWheelForMenu = 0;
|
||||
|
||||
InitializeCriticalSection(&m_navigationLock);
|
||||
InitializeCriticalSection(&m_registeredCallbackScenesCS);
|
||||
|
|
@ -803,6 +805,17 @@ void UIController::handleInput()
|
|||
if(iPad != ProfileManager.GetPrimaryPad()
|
||||
&& (!InputManager.IsPadConnected(iPad) || !InputManager.IsPadLocked(iPad)) ) continue;
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (iPad == 0 && !g_KBMInput.IsMouseGrabbed() && g_KBMInput.IsKBMActive())
|
||||
{
|
||||
m_windowsMouseWheelForMenu += g_KBMInput.ConsumeMouseWheel();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_windowsMouseWheelForMenu = 0;
|
||||
}
|
||||
#endif
|
||||
for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
|
||||
{
|
||||
handleKeyPress(iPad, key);
|
||||
|
|
@ -1024,20 +1037,24 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
|
|||
if (iPad == 0)
|
||||
{
|
||||
int vk = 0;
|
||||
switch (key)
|
||||
const bool keyboardTextEntryActive = Win64InGameKeyboard::IsActive();
|
||||
if (!keyboardTextEntryActive)
|
||||
{
|
||||
case ACTION_MENU_OK: case ACTION_MENU_A: vk = VK_RETURN; break;
|
||||
case ACTION_MENU_CANCEL: case ACTION_MENU_B: vk = VK_ESCAPE; break;
|
||||
case ACTION_MENU_UP: vk = VK_UP; break;
|
||||
case ACTION_MENU_DOWN: vk = VK_DOWN; break;
|
||||
case ACTION_MENU_LEFT: vk = VK_LEFT; break;
|
||||
case ACTION_MENU_RIGHT: vk = VK_RIGHT; break;
|
||||
case ACTION_MENU_X: vk = 'E'; break;
|
||||
case ACTION_MENU_Y: vk = VK_TAB; break;
|
||||
case ACTION_MENU_LEFT_SCROLL: vk = 'Q'; break;
|
||||
case ACTION_MENU_RIGHT_SCROLL: vk = 'R'; break;
|
||||
case ACTION_MENU_PAGEUP: vk = VK_PRIOR; break;
|
||||
case ACTION_MENU_PAGEDOWN: vk = VK_NEXT; break;
|
||||
switch (key)
|
||||
{
|
||||
case ACTION_MENU_OK: case ACTION_MENU_A: vk = VK_RETURN; break;
|
||||
case ACTION_MENU_CANCEL: case ACTION_MENU_B: vk = VK_ESCAPE; break;
|
||||
case ACTION_MENU_UP: vk = VK_UP; break;
|
||||
case ACTION_MENU_DOWN: vk = VK_DOWN; break;
|
||||
case ACTION_MENU_LEFT: vk = VK_LEFT; break;
|
||||
case ACTION_MENU_RIGHT: vk = VK_RIGHT; break;
|
||||
case ACTION_MENU_X: vk = 'E'; break;
|
||||
case ACTION_MENU_Y: vk = VK_TAB; break;
|
||||
case ACTION_MENU_LEFT_SCROLL: vk = 'Q'; break;
|
||||
case ACTION_MENU_RIGHT_SCROLL: vk = 'R'; break;
|
||||
case ACTION_MENU_PAGEUP: vk = VK_PRIOR; break;
|
||||
case ACTION_MENU_PAGEDOWN: vk = VK_NEXT; break;
|
||||
}
|
||||
}
|
||||
if (vk != 0)
|
||||
{
|
||||
|
|
@ -1046,7 +1063,7 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
|
|||
if (!pressed && !released && g_KBMInput.IsKeyDown(vk)) { down = true; }
|
||||
}
|
||||
|
||||
if ((key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed())
|
||||
if (!keyboardTextEntryActive && (key == ACTION_MENU_OK || key == ACTION_MENU_A) && !g_KBMInput.IsMouseGrabbed())
|
||||
{
|
||||
if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) { pressed = true; down = true; }
|
||||
if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) { released = true; down = false; }
|
||||
|
|
@ -1056,11 +1073,17 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
|
|||
// scroll
|
||||
if (!g_KBMInput.IsMouseGrabbed())
|
||||
{
|
||||
int wheel = g_KBMInput.GetMouseWheel();
|
||||
if ((key == ACTION_MENU_OTHER_STICK_UP && wheel >0) || (key == ACTION_MENU_OTHER_STICK_DOWN && wheel < 0))
|
||||
if (key == ACTION_MENU_OTHER_STICK_UP && m_windowsMouseWheelForMenu > 0)
|
||||
{
|
||||
pressed = true;
|
||||
down = true;
|
||||
--m_windowsMouseWheelForMenu;
|
||||
}
|
||||
else if (key == ACTION_MENU_OTHER_STICK_DOWN && m_windowsMouseWheelForMenu < 0)
|
||||
{
|
||||
pressed = true;
|
||||
down = true;
|
||||
++m_windowsMouseWheelForMenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ private:
|
|||
C4JThread *m_reloadSkinThread;
|
||||
bool m_navigateToHomeOnReload;
|
||||
int m_accumulatedTicks;
|
||||
int m_windowsMouseWheelForMenu;
|
||||
|
||||
D3D11_RECT m_customRenderingClearRect;
|
||||
|
||||
|
|
|
|||
|
|
@ -316,7 +316,11 @@ int UIScene_AnvilMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes)
|
|||
{
|
||||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
pClass->setEditNameValue((wchar_t *)pchText);
|
||||
pClass->m_itemName = (wchar_t *)pchText;
|
||||
pClass->updateItemName();
|
||||
|
|
@ -327,7 +331,9 @@ int UIScene_AnvilMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes)
|
|||
void UIScene_AnvilMenu::handleEditNamePressed()
|
||||
{
|
||||
setIgnoreInput(true);
|
||||
#if defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_TITLE_RENAME), m_textInputAnvil.getLabel(), (DWORD)m_iPad, 30, &UIScene_AnvilMenu::KeyboardCompleteCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#elif defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__
|
||||
int language = XGetLanguage();
|
||||
switch(language)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -420,13 +420,19 @@ void UIScene_CreateWorldMenu::handlePress(F64 controlId, F64 childId)
|
|||
case eControl_EditWorldName:
|
||||
{
|
||||
m_bIgnoreInput=true;
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_CREATE_NEW_WORLD), m_editWorldName.getLabel(), (DWORD)0, 25, &UIScene_CreateWorldMenu::KeyboardCompleteWorldNameCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#else
|
||||
InputManager.RequestKeyboard(app.GetString(IDS_CREATE_NEW_WORLD),m_editWorldName.getLabel(),(DWORD)0,25,&UIScene_CreateWorldMenu::KeyboardCompleteWorldNameCallback,this,C_4JInput::EKeyboardMode_Default);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case eControl_EditSeed:
|
||||
{
|
||||
m_bIgnoreInput=true;
|
||||
#ifdef __PS3__
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_CREATE_NEW_WORLD_SEED), m_editSeed.getLabel(), (DWORD)0, 60, &UIScene_CreateWorldMenu::KeyboardCompleteSeedCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#elif defined(__PS3__)
|
||||
int language = XGetLanguage();
|
||||
switch(language)
|
||||
{
|
||||
|
|
@ -761,7 +767,11 @@ int UIScene_CreateWorldMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,bo
|
|||
{
|
||||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
|
||||
if(pchText[0]!=0)
|
||||
{
|
||||
|
|
@ -789,7 +799,11 @@ int UIScene_CreateWorldMenu::KeyboardCompleteSeedCallback(LPVOID lpParam,bool bR
|
|||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
#endif
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
pClass->m_editSeed.setLabel((wchar_t *)pchText);
|
||||
pClass->m_MoreOptionsParams.seed = (wchar_t *)pchText;
|
||||
}
|
||||
|
|
@ -1095,6 +1109,7 @@ void UIScene_CreateWorldMenu::CreateGame(UIScene_CreateWorldMenu* pClass, DWORD
|
|||
StorageManager.ResetSaveData();
|
||||
// Make our next save default to the name of the level
|
||||
StorageManager.SetSaveTitle((wchar_t *)wWorldName.c_str());
|
||||
MinecraftServer::SetDeleteOnNoSaveForCurrentSession(true);
|
||||
|
||||
wstring wSeed;
|
||||
if(!pClass->m_MoreOptionsParams.seed.empty() )
|
||||
|
|
|
|||
|
|
@ -113,7 +113,11 @@ void UIScene_DebugCreateSchematic::handlePress(F64 controlId, F64 childId)
|
|||
case eControl_EndY:
|
||||
case eControl_EndZ:
|
||||
m_keyboardCallbackControl = (eControls)((int)controlId);
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(L"Enter something", L"", (DWORD)0, 25, &UIScene_DebugCreateSchematic::KeyboardCompleteCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#else
|
||||
InputManager.RequestKeyboard(L"Enter something",L"",(DWORD)0,25,&UIScene_DebugCreateSchematic::KeyboardCompleteCallback,this,C_4JInput::EKeyboardMode_Default);
|
||||
#endif
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
|
@ -140,7 +144,11 @@ int UIScene_DebugCreateSchematic::KeyboardCompleteCallback(LPVOID lpParam,bool b
|
|||
|
||||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
|
||||
if(pchText[0]!=0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,7 +101,11 @@ void UIScene_DebugSetCamera::handlePress(F64 controlId, F64 childId)
|
|||
case eControl_YRot:
|
||||
case eControl_Elevation:
|
||||
m_keyboardCallbackControl = (eControls)((int)controlId);
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(L"Enter something", L"", (DWORD)0, 25, &UIScene_DebugSetCamera::KeyboardCompleteCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#else
|
||||
InputManager.RequestKeyboard(L"Enter something",L"",(DWORD)0,25,&UIScene_DebugSetCamera::KeyboardCompleteCallback,this,C_4JInput::EKeyboardMode_Default);
|
||||
#endif
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
|
@ -121,7 +125,11 @@ int UIScene_DebugSetCamera::KeyboardCompleteCallback(LPVOID lpParam,bool bRes)
|
|||
UIScene_DebugSetCamera *pClass=(UIScene_DebugSetCamera *)lpParam;
|
||||
uint16_t pchText[2048];//[128];
|
||||
ZeroMemory(pchText, 2048/*128*/ * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
|
||||
if(pchText[0]!=0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,7 +81,37 @@ UIScene_FullscreenProgress::~UIScene_FullscreenProgress()
|
|||
m_parentLayer->removeComponent(eUIComponent_Panorama);
|
||||
m_parentLayer->removeComponent(eUIComponent_Logo);
|
||||
|
||||
delete thread;
|
||||
if( thread != NULL )
|
||||
{
|
||||
int code = thread->GetExitCode();
|
||||
DWORD exitcode = *((DWORD *)&code);
|
||||
|
||||
if( exitcode == STILL_ACTIVE && m_cancelFunc != NULL && !m_bWasCancelled )
|
||||
{
|
||||
m_bWasCancelled = true;
|
||||
m_cancelFunc(m_cancelFuncParam);
|
||||
}
|
||||
|
||||
if( exitcode == STILL_ACTIVE )
|
||||
{
|
||||
DWORD waitResult = thread->WaitForCompletion(m_bWaitForThreadToDelete ? INFINITE : 5000);
|
||||
if( waitResult == WAIT_TIMEOUT )
|
||||
{
|
||||
//app.DebugPrintf("UIScene_FullscreenProgress: skipping active thread delete to avoid shutdown race\n");
|
||||
thread = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
delete m_CompletionData;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#define UPDATE_PLAYERS_TIMER_ID 0
|
||||
#define UPDATE_PLAYERS_TIMER_TIME 30000
|
||||
#define CONNECT_POLL_TIMER_ID 1
|
||||
#define CONNECT_POLL_TIMER_TIME 100
|
||||
|
||||
UIScene_JoinMenu::UIScene_JoinMenu(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||
{
|
||||
|
|
@ -524,10 +526,14 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass)
|
|||
#endif
|
||||
CGameNetworkManager::eJoinGameResult result = g_NetworkManager.JoinGame( pClass->m_selectedSession, dwLocalUsersMask );
|
||||
|
||||
// Alert the app the we no longer want to be informed of ethernet connections
|
||||
app.SetLiveLinkRequired( false );
|
||||
|
||||
if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||
if( result == CGameNetworkManager::JOINGAME_PENDING )
|
||||
{
|
||||
pClass->m_bIgnoreInput = true;
|
||||
pClass->addTimer(CONNECT_POLL_TIMER_ID, CONNECT_POLL_TIMER_TIME);
|
||||
}
|
||||
else if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||
{
|
||||
int exitReasonStringId = -1;
|
||||
switch(result)
|
||||
|
|
@ -558,6 +564,22 @@ void UIScene_JoinMenu::handleTimerComplete(int id)
|
|||
{
|
||||
switch(id)
|
||||
{
|
||||
case CONNECT_POLL_TIMER_ID:
|
||||
{
|
||||
if (g_NetworkManager.IsJoinPending())
|
||||
{
|
||||
addTimer(CONNECT_POLL_TIMER_ID, CONNECT_POLL_TIMER_TIME);
|
||||
}
|
||||
else if (!g_NetworkManager.IsInSession())
|
||||
{
|
||||
m_bIgnoreInput = false;
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0] = IDS_CONFIRM_OK;
|
||||
ui.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
|
||||
ui.NavigateBack(m_iPad);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_PLAYERS_TIMER_ID:
|
||||
{
|
||||
#if TO_BE_IMPLEMENTED
|
||||
|
|
|
|||
|
|
@ -1,19 +1,357 @@
|
|||
#include "stdafx.h"
|
||||
#include "UI.h"
|
||||
#include "UIScene_Keyboard.h"
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
Win64InGameKeyboard::KeyboardCallback g_keyboardCallback = NULL;
|
||||
void *g_keyboardCallbackParam = NULL;
|
||||
wchar_t *g_keyboardOutputBuffer = NULL;
|
||||
unsigned int g_keyboardOutputBufferChars = 0;
|
||||
bool g_keyboardActive = false;
|
||||
std::wstring g_keyboardLastText;
|
||||
unsigned int g_keyboardMaxChars = 1;
|
||||
bool g_keyboardSubmitRequested = false;
|
||||
bool g_keyboardCancelRequested = false;
|
||||
bool g_keyboardTextChanged = false;
|
||||
int g_keyboardCursorLeftRequests = 0;
|
||||
int g_keyboardCursorRightRequests = 0;
|
||||
std::deque<wchar_t> g_keyboardChars;
|
||||
CRITICAL_SECTION g_keyboardCS;
|
||||
volatile LONG g_keyboardCSInitState = 0;
|
||||
|
||||
void EnsureKeyboardLock()
|
||||
{
|
||||
if (g_keyboardCSInitState == 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (InterlockedCompareExchange(&g_keyboardCSInitState, 1, 0) == 0)
|
||||
{
|
||||
InitializeCriticalSection(&g_keyboardCS);
|
||||
InterlockedExchange(&g_keyboardCSInitState, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
while (g_keyboardCSInitState != 2)
|
||||
{
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::Request(const wchar_t *title,
|
||||
const wchar_t *initialText,
|
||||
unsigned int iPad,
|
||||
unsigned int maxChars,
|
||||
KeyboardCallback callback,
|
||||
void *callbackParam,
|
||||
int keyboardMode,
|
||||
wchar_t *outputBuffer,
|
||||
unsigned int outputBufferChars)
|
||||
{
|
||||
(void)keyboardMode;
|
||||
EnsureKeyboardLock();
|
||||
|
||||
if (g_keyboardActive)
|
||||
{
|
||||
Complete(false, L"");
|
||||
}
|
||||
|
||||
UIScene_KeyboardInitData *initData = new UIScene_KeyboardInitData();
|
||||
initData->title = title != NULL ? title : L"";
|
||||
initData->initialText = initialText != NULL ? initialText : L"";
|
||||
initData->maxChars = (maxChars > 0) ? maxChars : 1;
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
g_keyboardCallback = callback;
|
||||
g_keyboardCallbackParam = callbackParam;
|
||||
g_keyboardOutputBuffer = outputBuffer;
|
||||
g_keyboardOutputBufferChars = outputBufferChars;
|
||||
g_keyboardActive = true;
|
||||
g_keyboardLastText = initData->initialText;
|
||||
g_keyboardMaxChars = initData->maxChars;
|
||||
g_keyboardSubmitRequested = false;
|
||||
g_keyboardCancelRequested = false;
|
||||
g_keyboardTextChanged = false;
|
||||
g_keyboardCursorLeftRequests = 0;
|
||||
g_keyboardCursorRightRequests = 0;
|
||||
g_keyboardChars.clear();
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
ui.NavigateToScene((int)iPad, eUIScene_Keyboard, initData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win64InGameKeyboard::Complete(bool accepted, const wchar_t *text)
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
KeyboardCallback callback = NULL;
|
||||
void *callbackParam = NULL;
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
if (!g_keyboardActive)
|
||||
{
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (accepted && text != NULL)
|
||||
{
|
||||
g_keyboardLastText = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_keyboardLastText.clear();
|
||||
}
|
||||
|
||||
if (g_keyboardOutputBuffer != NULL && g_keyboardOutputBufferChars > 0)
|
||||
{
|
||||
if (accepted)
|
||||
{
|
||||
wcsncpy_s(g_keyboardOutputBuffer, g_keyboardOutputBufferChars, g_keyboardLastText.c_str(), _TRUNCATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_keyboardOutputBuffer[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
callback = g_keyboardCallback;
|
||||
callbackParam = g_keyboardCallbackParam;
|
||||
|
||||
g_keyboardCallback = NULL;
|
||||
g_keyboardCallbackParam = NULL;
|
||||
g_keyboardOutputBuffer = NULL;
|
||||
g_keyboardOutputBufferChars = 0;
|
||||
g_keyboardActive = false;
|
||||
g_keyboardMaxChars = 1;
|
||||
g_keyboardSubmitRequested = false;
|
||||
g_keyboardCancelRequested = false;
|
||||
g_keyboardTextChanged = false;
|
||||
g_keyboardCursorLeftRequests = 0;
|
||||
g_keyboardCursorRightRequests = 0;
|
||||
g_keyboardChars.clear();
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
callback(callbackParam, accepted);
|
||||
}
|
||||
}
|
||||
|
||||
void Win64InGameKeyboard::GetText(uint16_t *utf16Text)
|
||||
{
|
||||
if (utf16Text == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
wchar_t *dest = (wchar_t *)utf16Text;
|
||||
const wchar_t *src = g_keyboardLastText.c_str();
|
||||
while ((*dest++ = *src++) != 0)
|
||||
{
|
||||
}
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
}
|
||||
|
||||
void Win64InGameKeyboard::OnChar(wchar_t ch)
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
if (!g_keyboardActive)
|
||||
{
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch == L'\r' || ch == L'\n')
|
||||
{
|
||||
g_keyboardSubmitRequested = true;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch == L'\b')
|
||||
{
|
||||
if (!g_keyboardLastText.empty())
|
||||
{
|
||||
g_keyboardLastText.erase(g_keyboardLastText.length() - 1, 1);
|
||||
g_keyboardTextChanged = true;
|
||||
}
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch >= 32 && g_keyboardLastText.length() < g_keyboardMaxChars)
|
||||
{
|
||||
g_keyboardLastText.push_back(ch);
|
||||
g_keyboardTextChanged = true;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
}
|
||||
|
||||
void Win64InGameKeyboard::OnVirtualKeyDown(unsigned int vk)
|
||||
{
|
||||
const unsigned int kVirtualKeyLeft = 0x25;
|
||||
const unsigned int kVirtualKeyRight = 0x27;
|
||||
const unsigned int kVirtualKeyEscape = 0x1B;
|
||||
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
if (!g_keyboardActive)
|
||||
{
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vk == kVirtualKeyLeft)
|
||||
{
|
||||
++g_keyboardCursorLeftRequests;
|
||||
}
|
||||
else if (vk == kVirtualKeyRight)
|
||||
{
|
||||
++g_keyboardCursorRightRequests;
|
||||
}
|
||||
else if (vk == kVirtualKeyEscape)
|
||||
{
|
||||
g_keyboardCancelRequested = true;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::ConsumeSubmitRequested()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool submitRequested = g_keyboardSubmitRequested;
|
||||
g_keyboardSubmitRequested = false;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
return submitRequested;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::ConsumeTextChanged()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool textChanged = g_keyboardTextChanged;
|
||||
g_keyboardTextChanged = false;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
return textChanged;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::ConsumeCursorLeftRequested()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool requested = (g_keyboardCursorLeftRequests > 0);
|
||||
if (requested)
|
||||
--g_keyboardCursorLeftRequests;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
return requested;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::ConsumeCursorRightRequested()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool requested = (g_keyboardCursorRightRequests > 0);
|
||||
if (requested)
|
||||
--g_keyboardCursorRightRequests;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
return requested;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::ConsumeCancelRequested()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool requested = g_keyboardCancelRequested;
|
||||
g_keyboardCancelRequested = false;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
|
||||
return requested;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::PopChar(wchar_t *outCh)
|
||||
{
|
||||
if (outCh == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
if (g_keyboardChars.empty())
|
||||
{
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return false;
|
||||
}
|
||||
|
||||
*outCh = g_keyboardChars.front();
|
||||
g_keyboardChars.pop_front();
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Win64InGameKeyboard::IsActive()
|
||||
{
|
||||
EnsureKeyboardLock();
|
||||
|
||||
EnterCriticalSection(&g_keyboardCS);
|
||||
const bool isActive = g_keyboardActive;
|
||||
LeaveCriticalSection(&g_keyboardCS);
|
||||
return isActive;
|
||||
}
|
||||
|
||||
#define KEYBOARD_DONE_TIMER_ID 0
|
||||
#define KEYBOARD_DONE_TIMER_TIME 100
|
||||
#define KEYBOARD_BACKGROUND_OPACITY 0.72f
|
||||
|
||||
UIScene_Keyboard::UIScene_Keyboard(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||
{
|
||||
UIScene_KeyboardInitData *params = (UIScene_KeyboardInitData *)initData;
|
||||
wstring title = L"Enter Text";
|
||||
wstring initialText = L"";
|
||||
unsigned int maxChars = 15;
|
||||
if (params != NULL)
|
||||
{
|
||||
if (!params->title.empty())
|
||||
title = params->title;
|
||||
initialText = params->initialText;
|
||||
if (params->maxChars > 0)
|
||||
maxChars = params->maxChars;
|
||||
delete params;
|
||||
}
|
||||
|
||||
// Setup all the Iggy references we need for this scene
|
||||
initialiseMovie();
|
||||
|
||||
m_EnterTextLabel.init(L"Enter Sign Text");
|
||||
m_EnterTextLabel.init(title);
|
||||
|
||||
m_KeyboardTextInput.init(L"", -1);
|
||||
m_KeyboardTextInput.SetCharLimit(15);
|
||||
m_KeyboardTextInput.init(initialText, -1);
|
||||
m_KeyboardTextInput.SetCharLimit((int)maxChars);
|
||||
m_charLimit = (int)maxChars;
|
||||
|
||||
m_ButtonSpace.init(L"Space", -1);
|
||||
m_ButtonCursorLeft.init(L"Cursor Left", -1);
|
||||
|
|
@ -37,15 +375,78 @@ UIScene_Keyboard::UIScene_Keyboard(int iPad, void *initData, UILayer *parentLaye
|
|||
IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcInitFunctionButtons , 1 , value );
|
||||
|
||||
m_bKeyboardDonePressed = false;
|
||||
m_bKeyboardResultSent = false;
|
||||
m_pMenuBackground = NULL;
|
||||
|
||||
parentLayer->addComponent(iPad,eUIComponent_MenuBackground);
|
||||
m_pMenuBackground = parentLayer->addComponent(iPad,eUIComponent_MenuBackground);
|
||||
if (m_pMenuBackground != NULL)
|
||||
{
|
||||
m_pMenuBackground->setOpacity(KEYBOARD_BACKGROUND_OPACITY);
|
||||
}
|
||||
}
|
||||
|
||||
UIScene_Keyboard::~UIScene_Keyboard()
|
||||
{
|
||||
if (!m_bKeyboardResultSent && Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
Win64InGameKeyboard::Complete(false, L"");
|
||||
m_bKeyboardResultSent = true;
|
||||
}
|
||||
|
||||
if (m_pMenuBackground != NULL)
|
||||
{
|
||||
m_pMenuBackground->setOpacity(1.0f);
|
||||
m_pMenuBackground = NULL;
|
||||
}
|
||||
|
||||
m_parentLayer->removeComponent(eUIComponent_MenuBackground);
|
||||
}
|
||||
|
||||
void UIScene_Keyboard::tick()
|
||||
{
|
||||
UIScene::tick();
|
||||
|
||||
if (!Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Win64InGameKeyboard::ConsumeTextChanged())
|
||||
{
|
||||
std::vector<uint16_t> utf16Text((size_t)m_charLimit + 1u);
|
||||
ZeroMemory(&utf16Text[0], utf16Text.size() * sizeof(uint16_t));
|
||||
Win64InGameKeyboard::GetText(&utf16Text[0]);
|
||||
m_KeyboardTextInput.setLabel((wchar_t *)&utf16Text[0]);
|
||||
}
|
||||
|
||||
IggyDataValue result;
|
||||
while (Win64InGameKeyboard::ConsumeCursorLeftRequested())
|
||||
{
|
||||
IggyPlayerCallMethodRS(getMovie(), &result, IggyPlayerRootPath(getMovie()), m_funcCursorLeftButtonPressed, 0, NULL);
|
||||
}
|
||||
while (Win64InGameKeyboard::ConsumeCursorRightRequested())
|
||||
{
|
||||
IggyPlayerCallMethodRS(getMovie(), &result, IggyPlayerRootPath(getMovie()), m_funcCursorRightButtonPressed, 0, NULL);
|
||||
}
|
||||
|
||||
if (Win64InGameKeyboard::ConsumeCancelRequested())
|
||||
{
|
||||
if (!m_bKeyboardResultSent)
|
||||
{
|
||||
Win64InGameKeyboard::Complete(false, L"");
|
||||
m_bKeyboardResultSent = true;
|
||||
}
|
||||
navigateBack();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Win64InGameKeyboard::ConsumeSubmitRequested() && !m_bKeyboardDonePressed)
|
||||
{
|
||||
addTimer(KEYBOARD_DONE_TIMER_ID, KEYBOARD_DONE_TIMER_TIME);
|
||||
m_bKeyboardDonePressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
wstring UIScene_Keyboard::getMoviePath()
|
||||
{
|
||||
if(app.GetLocalPlayerCount() > 1 && !m_parentLayer->IsFullscreenGroup())
|
||||
|
|
@ -90,6 +491,12 @@ void UIScene_Keyboard::handleInput(int iPad, int key, bool repeat, bool pressed,
|
|||
switch(key)
|
||||
{
|
||||
case ACTION_MENU_CANCEL:
|
||||
case ACTION_MENU_B:
|
||||
if (!m_bKeyboardResultSent)
|
||||
{
|
||||
Win64InGameKeyboard::Complete(false, L"");
|
||||
m_bKeyboardResultSent = true;
|
||||
}
|
||||
navigateBack();
|
||||
handled = true;
|
||||
break;
|
||||
|
|
@ -173,6 +580,15 @@ void UIScene_Keyboard::handleTimerComplete(int id)
|
|||
|
||||
void UIScene_Keyboard::KeyboardDonePressed()
|
||||
{
|
||||
if (!m_bKeyboardResultSent)
|
||||
{
|
||||
std::vector<uint16_t> utf16Text((size_t)m_charLimit + 1u);
|
||||
ZeroMemory(&utf16Text[0], utf16Text.size() * sizeof(uint16_t));
|
||||
Win64InGameKeyboard::GetText(&utf16Text[0]);
|
||||
Win64InGameKeyboard::Complete(true, (wchar_t *)&utf16Text[0]);
|
||||
m_bKeyboardResultSent = true;
|
||||
}
|
||||
|
||||
// Debug
|
||||
app.DebugPrintf("UI Keyboard - DONE - [%ls]\n", m_KeyboardTextInput.getLabel());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "UIScene.h"
|
||||
#include "UIControl_Label.h"
|
||||
#include "UIControl_TextInput.h"
|
||||
#include "UIControl_Button.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct UIScene_KeyboardInitData
|
||||
{
|
||||
wstring title;
|
||||
wstring initialText;
|
||||
unsigned int maxChars;
|
||||
};
|
||||
|
||||
namespace Win64InGameKeyboard
|
||||
{
|
||||
typedef int (*KeyboardCallback)(void *, const bool);
|
||||
|
||||
bool Request(const wchar_t *title,
|
||||
const wchar_t *initialText,
|
||||
unsigned int iPad,
|
||||
unsigned int maxChars,
|
||||
KeyboardCallback callback,
|
||||
void *callbackParam,
|
||||
int keyboardMode,
|
||||
wchar_t *outputBuffer = NULL,
|
||||
unsigned int outputBufferChars = 0);
|
||||
|
||||
void Complete(bool accepted, const wchar_t *text);
|
||||
void GetText(uint16_t *utf16Text);
|
||||
void OnChar(wchar_t ch);
|
||||
void OnVirtualKeyDown(unsigned int vk);
|
||||
bool ConsumeSubmitRequested();
|
||||
bool ConsumeTextChanged();
|
||||
bool ConsumeCursorLeftRequested();
|
||||
bool ConsumeCursorRightRequested();
|
||||
bool ConsumeCancelRequested();
|
||||
bool PopChar(wchar_t *outCh);
|
||||
bool IsActive();
|
||||
}
|
||||
|
||||
class UIScene_Keyboard : public UIScene
|
||||
{
|
||||
private:
|
||||
bool m_bKeyboardDonePressed;
|
||||
bool m_bKeyboardResultSent;
|
||||
int m_charLimit;
|
||||
UIScene *m_pMenuBackground;
|
||||
|
||||
protected:
|
||||
UIControl_Label m_EnterTextLabel;
|
||||
|
|
@ -43,6 +84,7 @@ public:
|
|||
UIScene_Keyboard(int iPad, void *initData, UILayer *parentLayer);
|
||||
~UIScene_Keyboard();
|
||||
|
||||
virtual void tick();
|
||||
virtual void updateTooltips();
|
||||
|
||||
virtual bool allowRepeat(int key);
|
||||
|
|
@ -75,5 +117,5 @@ public:
|
|||
#endif
|
||||
|
||||
// Returns true if lower scenes in this scenes layer, or in any layer below this scenes layers should be hidden
|
||||
virtual bool hidesLowerScenes() { return false; }
|
||||
virtual bool hidesLowerScenes() { return true; }
|
||||
};
|
||||
|
|
@ -407,7 +407,11 @@ int UIScene_LaunchMoreOptionsMenu::KeyboardCompleteSeedCallback(LPVOID lpParam,b
|
|||
{
|
||||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
InputManager.GetText(pchText);
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
pClass->m_editSeed.setLabel((wchar_t *)pchText);
|
||||
pClass->m_params->seed = (wchar_t *)pchText;
|
||||
}
|
||||
|
|
@ -423,7 +427,9 @@ void UIScene_LaunchMoreOptionsMenu::handlePress(F64 controlId, F64 childId)
|
|||
case eControl_EditSeed:
|
||||
{
|
||||
m_bIgnoreInput=true;
|
||||
#ifdef __PS3__
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_CREATE_NEW_WORLD_SEED), m_editSeed.getLabel(), (DWORD)0, 60, &UIScene_LaunchMoreOptionsMenu::KeyboardCompleteSeedCallback, this, C_4JInput::EKeyboardMode_Default);
|
||||
#elif defined(__PS3__)
|
||||
int language = XGetLanguage();
|
||||
switch(language)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -882,11 +882,9 @@ void UIScene_LeaderboardsMenu::PopulateLeaderboard(LeaderboardManager::eStatsRet
|
|||
m_leaderboard.m_entries[i].m_row,
|
||||
m_leaderboard.m_entries[i].m_rank,
|
||||
m_leaderboard.m_entries[i].m_gamerTag,
|
||||
|
||||
true, // 4J-JEV: Has error message to display.
|
||||
|
||||
app.GetString(idsErrorMessage),
|
||||
L"", L"", L"", L"", L"", L""
|
||||
L"", L"", L"", L"", L"", L"",
|
||||
true // 4J-JEV: Has error message to display.
|
||||
);
|
||||
}
|
||||
else
|
||||
|
|
@ -896,19 +894,18 @@ void UIScene_LeaderboardsMenu::PopulateLeaderboard(LeaderboardManager::eStatsRet
|
|||
m_leaderboard.m_entries[i].m_row,
|
||||
m_leaderboard.m_entries[i].m_rank,
|
||||
m_leaderboard.m_entries[i].m_gamerTag,
|
||||
|
||||
// 4J-TomK | The bDisplayMessage Flag defines if Leaderboard Data should be
|
||||
// displayed (false) or if a specific message (true - when data is private for example)
|
||||
// should be displayed. The message itself should be passed on in col0!
|
||||
false,
|
||||
|
||||
m_leaderboard.m_entries[i].m_wcColumns[0],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[1],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[2],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[3],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[4],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[5],
|
||||
m_leaderboard.m_entries[i].m_wcColumns[6]
|
||||
m_leaderboard.m_entries[i].m_wcColumns[6],
|
||||
|
||||
// 4J-TomK | The bDisplayMessage Flag defines if Leaderboard Data should be
|
||||
// displayed (false) or if a specific message (true - when data is private for example)
|
||||
// should be displayed. The message itself should be passed on in col0!
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,104 @@ C4JStorage::SAVETRANSFER_FILE_DETAILS UIScene_LoadOrJoinMenu::m_debugTransferDet
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
static const int kAddServerNameMaxChars = 19;
|
||||
static const int kAddServerAddressMaxChars = 63;
|
||||
static const unsigned short kAddServerDefaultPort = 25565;
|
||||
|
||||
static void TrimWideInPlace(wchar_t *text)
|
||||
{
|
||||
if (text == NULL)
|
||||
return;
|
||||
|
||||
wchar_t *start = text;
|
||||
while (*start == L' ' || *start == L'\t' || *start == L'\r' || *start == L'\n')
|
||||
++start;
|
||||
|
||||
if (start != text)
|
||||
{
|
||||
memmove(text, start, (wcslen(start) + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
size_t len = wcslen(text);
|
||||
while (len > 0)
|
||||
{
|
||||
wchar_t ch = text[len - 1];
|
||||
if (ch == L' ' || ch == L'\t' || ch == L'\r' || ch == L'\n')
|
||||
text[--len] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseServerAddress(const wchar_t *input, char *outHost, size_t outHostSize, unsigned short *outPort)
|
||||
{
|
||||
if (input == NULL || outHost == NULL || outHostSize == 0 || outPort == NULL)
|
||||
return false;
|
||||
|
||||
outHost[0] = 0;
|
||||
*outPort = kAddServerDefaultPort;
|
||||
|
||||
wchar_t working[128];
|
||||
wcsncpy_s(working, sizeof(working) / sizeof(working[0]), input, _TRUNCATE);
|
||||
TrimWideInPlace(working);
|
||||
if (working[0] == 0)
|
||||
return false;
|
||||
|
||||
const wchar_t prefix[] = L"minecraft://";
|
||||
if (_wcsnicmp(working, prefix, wcslen(prefix)) == 0)
|
||||
{
|
||||
wchar_t stripped[128];
|
||||
wcsncpy_s(stripped, sizeof(stripped) / sizeof(stripped[0]), working + wcslen(prefix), _TRUNCATE);
|
||||
wcsncpy_s(working, sizeof(working) / sizeof(working[0]), stripped, _TRUNCATE);
|
||||
TrimWideInPlace(working);
|
||||
}
|
||||
|
||||
wchar_t *slash = wcschr(working, L'/');
|
||||
if (slash != NULL)
|
||||
*slash = 0;
|
||||
|
||||
wchar_t *firstColon = wcschr(working, L':');
|
||||
wchar_t *lastColon = wcsrchr(working, L':');
|
||||
if (firstColon != NULL && firstColon != lastColon)
|
||||
return false;
|
||||
|
||||
if (lastColon != NULL)
|
||||
{
|
||||
const wchar_t *portText = lastColon + 1;
|
||||
if (*portText == 0)
|
||||
return false;
|
||||
|
||||
for (const wchar_t *it = portText; *it != 0; ++it)
|
||||
{
|
||||
if (*it < L'0' || *it > L'9')
|
||||
return false;
|
||||
}
|
||||
|
||||
int parsedPort = _wtoi(portText);
|
||||
if (parsedPort <= 0 || parsedPort > 65535)
|
||||
return false;
|
||||
|
||||
*outPort = (unsigned short)parsedPort;
|
||||
*lastColon = 0;
|
||||
TrimWideInPlace(working);
|
||||
}
|
||||
|
||||
if (working[0] == 0)
|
||||
return false;
|
||||
|
||||
size_t converted = 0;
|
||||
errno_t convRes = wcstombs_s(&converted, outHost, outHostSize, working, _TRUNCATE);
|
||||
if (convRes != 0 || outHost[0] == 0)
|
||||
return false;
|
||||
|
||||
if (strchr(outHost, ' ') != NULL || strchr(outHost, '\t') != NULL)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
int UIScene_LoadOrJoinMenu::LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes)
|
||||
{
|
||||
UIScene_LoadOrJoinMenu *pClass= (UIScene_LoadOrJoinMenu *)lpParam;
|
||||
|
|
@ -124,6 +222,13 @@ UIScene_LoadOrJoinMenu::UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer
|
|||
m_bSavesDisplayed=false;
|
||||
m_saveDetails = NULL;
|
||||
m_iSaveDetailsCount = 0;
|
||||
#ifdef _WINDOWS64
|
||||
m_pendingServerName[0] = 0;
|
||||
m_bAddServerFlowActive = false;
|
||||
m_bPendingAddServerAddressKeyboard = false;
|
||||
m_bPendingAddServerAddressShowInvalid = false;
|
||||
m_pendingServerAddressInput[0] = 0;
|
||||
#endif
|
||||
m_iTexturePacksNotInstalled = 0;
|
||||
m_bCopying = false;
|
||||
m_bCopyingCancelled = false;
|
||||
|
|
@ -310,9 +415,25 @@ void UIScene_LoadOrJoinMenu::updateTooltips()
|
|||
int iY = -1;
|
||||
int iLB = -1;
|
||||
int iX=-1;
|
||||
#ifdef _WINDOWS64
|
||||
bool canDeleteSavedServer = false;
|
||||
#endif
|
||||
if (DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
int selectedIndex = m_buttonListGames.getCurrentSelection();
|
||||
if (!IsAddServerListIndex(selectedIndex))
|
||||
{
|
||||
iY = IDS_TOOLTIPS_VIEW_GAMERCARD;
|
||||
if (CanRemoveSavedServerAtListIndex(selectedIndex))
|
||||
{
|
||||
iRB = IDS_TOOLTIPS_DELETE;
|
||||
canDeleteSavedServer = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
iY = IDS_TOOLTIPS_VIEW_GAMERCARD;
|
||||
#endif
|
||||
}
|
||||
else if (DoesSavesListHaveFocus())
|
||||
{
|
||||
|
|
@ -385,6 +506,13 @@ void UIScene_LoadOrJoinMenu::updateTooltips()
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (canDeleteSavedServer)
|
||||
{
|
||||
iX = IDS_TOOLTIPS_DELETE;
|
||||
}
|
||||
#endif
|
||||
|
||||
ui.SetTooltips( DEFAULT_XUI_MENU_USER, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_BACK, iX, iY,-1,-1,iLB,iRB);
|
||||
}
|
||||
|
||||
|
|
@ -543,6 +671,28 @@ void UIScene_LoadOrJoinMenu::tick()
|
|||
{
|
||||
UIScene::tick();
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (m_bPendingAddServerAddressKeyboard && hasFocus(m_iPad) && !Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
m_bPendingAddServerAddressKeyboard = false;
|
||||
const wchar_t *addressTitle = m_bPendingAddServerAddressShowInvalid ? L"Invalid Address - use host[:port]" : L"Server Address (host[:port])";
|
||||
m_bPendingAddServerAddressShowInvalid = false;
|
||||
m_bIgnoreInput = true;
|
||||
if (!Win64InGameKeyboard::Request(addressTitle,
|
||||
m_pendingServerAddressInput,
|
||||
(DWORD)m_iPad,
|
||||
kAddServerAddressMaxChars,
|
||||
&UIScene_LoadOrJoinMenu::AddServerAddressKeyboardCallback,
|
||||
this,
|
||||
C_4JInput::EKeyboardMode_Default))
|
||||
{
|
||||
m_bAddServerFlowActive = false;
|
||||
m_bIgnoreInput = false;
|
||||
updateTooltips();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined _WINDOWS64 || defined __PSVITA__)
|
||||
if(m_bExitScene) // navigate forward or back
|
||||
{
|
||||
|
|
@ -586,7 +736,7 @@ void UIScene_LoadOrJoinMenu::tick()
|
|||
|
||||
if(m_saveDetails!=NULL)
|
||||
{
|
||||
for(unsigned int i = 0; i < m_iSaveDetailsCount; ++i)
|
||||
for(int i = 0; i < m_iSaveDetailsCount; ++i)
|
||||
{
|
||||
if(m_saveDetails[i].pbThumbnailData!=NULL)
|
||||
{
|
||||
|
|
@ -598,7 +748,7 @@ void UIScene_LoadOrJoinMenu::tick()
|
|||
m_saveDetails = new SaveListDetails[m_pSaveDetails->iSaveC];
|
||||
|
||||
m_iSaveDetailsCount = m_pSaveDetails->iSaveC;
|
||||
for(unsigned int i = 0; i < m_pSaveDetails->iSaveC; ++i)
|
||||
for(int i = 0; i < m_pSaveDetails->iSaveC; ++i)
|
||||
{
|
||||
#if defined(_XBOX_ONE)
|
||||
m_spaceIndicatorSaves.addSave(m_pSaveDetails->SaveInfoA[i].totalSize);
|
||||
|
|
@ -941,7 +1091,25 @@ void UIScene_LoadOrJoinMenu::AddDefaultButtons()
|
|||
|
||||
void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
if (m_bIgnoreInput)
|
||||
{
|
||||
if (m_bAddServerFlowActive && (key == ACTION_MENU_CANCEL || key == ACTION_MENU_B) && pressed)
|
||||
{
|
||||
m_bAddServerFlowActive = false;
|
||||
m_bPendingAddServerAddressKeyboard = false;
|
||||
m_bPendingAddServerAddressShowInvalid = false;
|
||||
m_pendingServerName[0] = 0;
|
||||
m_pendingServerAddressInput[0] = 0;
|
||||
m_bIgnoreInput = false;
|
||||
updateTooltips();
|
||||
handled = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(m_bIgnoreInput) return;
|
||||
#endif
|
||||
|
||||
// if we're retrieving save info, ignore key presses
|
||||
if(!m_bSavesDisplayed) return;
|
||||
|
|
@ -962,6 +1130,18 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
|
|||
}
|
||||
break;
|
||||
case ACTION_MENU_X:
|
||||
#ifdef _WINDOWS64
|
||||
if (DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
|
||||
{
|
||||
int selectedIndex = m_buttonListGames.getCurrentSelection();
|
||||
if (RemoveSavedServerAtListIndex(selectedIndex))
|
||||
{
|
||||
ui.PlayUISFX(eSFX_Press);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if TO_BE_IMPLEMENTED
|
||||
// Change device
|
||||
// Fix for #12531 - TCR 001: BAS Game Stability: When a player selects to change a storage
|
||||
|
|
@ -1041,6 +1221,18 @@ void UIScene_LoadOrJoinMenu::handleInput(int iPad, int key, bool repeat, bool pr
|
|||
break;
|
||||
|
||||
case ACTION_MENU_RIGHT_SCROLL:
|
||||
#ifdef _WINDOWS64
|
||||
if (DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0 && m_currentSessions != NULL)
|
||||
{
|
||||
int selectedIndex = m_buttonListGames.getCurrentSelection();
|
||||
if (RemoveSavedServerAtListIndex(selectedIndex))
|
||||
{
|
||||
ui.PlayUISFX(eSFX_Press);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(DoesSavesListHaveFocus())
|
||||
{
|
||||
// 4J-PB - check we are on a valid save
|
||||
|
|
@ -1169,7 +1361,11 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
|
|||
{
|
||||
uint16_t ui16Text[128];
|
||||
ZeroMemory(ui16Text, 128 * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(ui16Text);
|
||||
#else
|
||||
InputManager.GetText(ui16Text);
|
||||
#endif
|
||||
|
||||
// check the name is valid
|
||||
if(ui16Text[0]!=0)
|
||||
|
|
@ -1206,11 +1402,11 @@ void UIScene_LoadOrJoinMenu::handleFocusChange(F64 controlId, F64 childId)
|
|||
switch((int)controlId)
|
||||
{
|
||||
case eControl_GamesList:
|
||||
m_iGameListIndex = childId;
|
||||
m_iGameListIndex = (int)childId;
|
||||
m_buttonListGames.updateChildFocus( (int) childId );
|
||||
break;
|
||||
case eControl_SavesList:
|
||||
m_iSaveListIndex = childId;
|
||||
m_iSaveListIndex = (int)childId;
|
||||
m_bUpdateSaveSize = true;
|
||||
break;
|
||||
};
|
||||
|
|
@ -1334,8 +1530,6 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
|
|||
break;
|
||||
case eControl_GamesList:
|
||||
{
|
||||
m_bIgnoreInput=true;
|
||||
|
||||
m_eAction = eAction_JoinGame;
|
||||
|
||||
//CD - Added for audio
|
||||
|
|
@ -1344,7 +1538,28 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
|
|||
{
|
||||
int nIndex = (int)childId;
|
||||
m_iGameListIndex = nIndex;
|
||||
CheckAndJoinGame(nIndex);
|
||||
#ifdef _WINDOWS64
|
||||
if (IsAddServerListIndex(nIndex))
|
||||
{
|
||||
BeginAddServerFlow();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_currentSessions == NULL || nIndex < 0 || nIndex >= (int)m_currentSessions->size())
|
||||
{
|
||||
m_bIgnoreInput = false;
|
||||
updateTooltips();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bIgnoreInput = true;
|
||||
CheckAndJoinGame(nIndex);
|
||||
}
|
||||
}
|
||||
#else
|
||||
m_bIgnoreInput=true;
|
||||
CheckAndJoinGame(nIndex);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -1352,9 +1567,233 @@ void UIScene_LoadOrJoinMenu::handlePress(F64 controlId, F64 childId)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
bool UIScene_LoadOrJoinMenu::IsAddServerListIndex(int listIndex)
|
||||
{
|
||||
if (listIndex < 0)
|
||||
return false;
|
||||
|
||||
int itemCount = m_buttonListGames.getItemCount();
|
||||
if (itemCount <= 0)
|
||||
return false;
|
||||
|
||||
return (listIndex == (itemCount - 1));
|
||||
}
|
||||
|
||||
bool UIScene_LoadOrJoinMenu::TryGetSavedServerAtListIndex(int listIndex, char *pHost, int hostSize, unsigned short *pPort)
|
||||
{
|
||||
if (m_currentSessions == NULL)
|
||||
return false;
|
||||
|
||||
if (listIndex < 0 || listIndex >= (int)m_currentSessions->size())
|
||||
return false;
|
||||
|
||||
if (IsAddServerListIndex(listIndex))
|
||||
return false;
|
||||
|
||||
FriendSessionInfo *selectedSession = m_currentSessions->at(listIndex);
|
||||
if (selectedSession == NULL)
|
||||
return false;
|
||||
|
||||
if (selectedSession->data.hostIP[0] == 0)
|
||||
return false;
|
||||
|
||||
if (selectedSession->data.hostPort <= 0 || selectedSession->data.hostPort > 65535)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < app.GetSavedServerCount(m_iPad); ++i)
|
||||
{
|
||||
char savedName[WIN64_SAVED_SERVER_NAME_CHARS];
|
||||
char savedHost[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
unsigned short savedPort = 0;
|
||||
if (!app.GetSavedServer(m_iPad, i, savedName, sizeof(savedName), savedHost, sizeof(savedHost), &savedPort))
|
||||
continue;
|
||||
|
||||
if (_stricmp(savedHost, selectedSession->data.hostIP) == 0 && savedPort == (unsigned short)selectedSession->data.hostPort)
|
||||
{
|
||||
if (pHost != NULL && hostSize > 0)
|
||||
{
|
||||
strncpy_s(pHost, hostSize, savedHost, _TRUNCATE);
|
||||
}
|
||||
|
||||
if (pPort != NULL)
|
||||
{
|
||||
*pPort = savedPort;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UIScene_LoadOrJoinMenu::CanRemoveSavedServerAtListIndex(int listIndex)
|
||||
{
|
||||
return TryGetSavedServerAtListIndex(listIndex, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
bool UIScene_LoadOrJoinMenu::RemoveSavedServerAtListIndex(int listIndex)
|
||||
{
|
||||
char host[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
unsigned short port = 0;
|
||||
if (!TryGetSavedServerAtListIndex(listIndex, host, sizeof(host), &port))
|
||||
return false;
|
||||
|
||||
if (!app.RemoveSavedServer(m_iPad, host, port))
|
||||
return false;
|
||||
|
||||
app.CheckGameSettingsChanged(true, m_iPad);
|
||||
g_NetworkManager.ForceFriendsSessionRefresh();
|
||||
UpdateGamesList();
|
||||
|
||||
int itemCount = m_buttonListGames.getItemCount();
|
||||
if (itemCount > 0)
|
||||
{
|
||||
if (listIndex >= itemCount)
|
||||
listIndex = itemCount - 1;
|
||||
|
||||
if (listIndex < 0)
|
||||
listIndex = 0;
|
||||
|
||||
m_buttonListGames.setCurrentSelection(listIndex);
|
||||
}
|
||||
|
||||
updateTooltips();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UIScene_LoadOrJoinMenu::BeginAddServerFlow()
|
||||
{
|
||||
m_pendingServerName[0] = 0;
|
||||
m_bAddServerFlowActive = true;
|
||||
m_bPendingAddServerAddressKeyboard = false;
|
||||
m_bPendingAddServerAddressShowInvalid = false;
|
||||
m_pendingServerAddressInput[0] = 0;
|
||||
m_bIgnoreInput = true;
|
||||
|
||||
if (!Win64InGameKeyboard::Request(L"Add Server Name",
|
||||
L"",
|
||||
(DWORD)m_iPad,
|
||||
kAddServerNameMaxChars,
|
||||
&UIScene_LoadOrJoinMenu::AddServerNameKeyboardCallback,
|
||||
this,
|
||||
C_4JInput::EKeyboardMode_Default))
|
||||
{
|
||||
m_bAddServerFlowActive = false;
|
||||
m_bIgnoreInput = false;
|
||||
updateTooltips();
|
||||
}
|
||||
}
|
||||
|
||||
void UIScene_LoadOrJoinMenu::QueueAddServerAddressKeyboard(const wchar_t *initialText, bool showInvalidMessage)
|
||||
{
|
||||
if (initialText != NULL)
|
||||
wcsncpy_s(m_pendingServerAddressInput, 128, initialText, _TRUNCATE);
|
||||
else
|
||||
m_pendingServerAddressInput[0] = 0;
|
||||
|
||||
m_bPendingAddServerAddressShowInvalid = showInvalidMessage;
|
||||
m_bPendingAddServerAddressKeyboard = true;
|
||||
}
|
||||
|
||||
int UIScene_LoadOrJoinMenu::AddServerNameKeyboardCallback(LPVOID lpParam, bool bRes)
|
||||
{
|
||||
UIScene_LoadOrJoinMenu *pClass = (UIScene_LoadOrJoinMenu *)lpParam;
|
||||
if (pClass == NULL)
|
||||
return 0;
|
||||
|
||||
if (!bRes)
|
||||
{
|
||||
pClass->m_bAddServerFlowActive = false;
|
||||
pClass->m_bPendingAddServerAddressKeyboard = false;
|
||||
pClass->m_bPendingAddServerAddressShowInvalid = false;
|
||||
pClass->m_bIgnoreInput = false;
|
||||
pClass->updateTooltips();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t ui16Text[128];
|
||||
ZeroMemory(ui16Text, sizeof(ui16Text));
|
||||
Win64InGameKeyboard::GetText(ui16Text);
|
||||
TrimWideInPlace((wchar_t *)ui16Text);
|
||||
|
||||
if (((wchar_t *)ui16Text)[0] == 0)
|
||||
{
|
||||
wcsncpy_s((wchar_t *)ui16Text, 128, L"Saved Server", _TRUNCATE);
|
||||
}
|
||||
|
||||
wcsncpy_s(pClass->m_pendingServerName, 64, (wchar_t *)ui16Text, _TRUNCATE);
|
||||
|
||||
pClass->m_bIgnoreInput = true;
|
||||
pClass->QueueAddServerAddressKeyboard(L"");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UIScene_LoadOrJoinMenu::AddServerAddressKeyboardCallback(LPVOID lpParam, bool bRes)
|
||||
{
|
||||
UIScene_LoadOrJoinMenu *pClass = (UIScene_LoadOrJoinMenu *)lpParam;
|
||||
if (pClass == NULL)
|
||||
return 0;
|
||||
|
||||
if (!bRes)
|
||||
{
|
||||
pClass->m_bAddServerFlowActive = false;
|
||||
pClass->m_bPendingAddServerAddressKeyboard = false;
|
||||
pClass->m_bPendingAddServerAddressShowInvalid = false;
|
||||
pClass->m_bIgnoreInput = false;
|
||||
pClass->updateTooltips();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t ui16Text[128];
|
||||
ZeroMemory(ui16Text, sizeof(ui16Text));
|
||||
Win64InGameKeyboard::GetText(ui16Text);
|
||||
TrimWideInPlace((wchar_t *)ui16Text);
|
||||
|
||||
char host[WIN64_SAVED_SERVER_HOST_CHARS];
|
||||
unsigned short port = kAddServerDefaultPort;
|
||||
if (!ParseServerAddress((wchar_t *)ui16Text, host, sizeof(host), &port))
|
||||
{
|
||||
pClass->m_bIgnoreInput = true;
|
||||
pClass->QueueAddServerAddressKeyboard((wchar_t *)ui16Text, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char name[WIN64_SAVED_SERVER_NAME_CHARS];
|
||||
name[0] = 0;
|
||||
size_t converted = 0;
|
||||
wcstombs_s(&converted, name, sizeof(name), pClass->m_pendingServerName, _TRUNCATE);
|
||||
|
||||
if (!app.AddOrUpdateSavedServer(pClass->m_iPad, name, host, port))
|
||||
{
|
||||
pClass->m_bIgnoreInput = true;
|
||||
pClass->QueueAddServerAddressKeyboard((wchar_t *)ui16Text, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
app.CheckGameSettingsChanged(true, pClass->m_iPad);
|
||||
g_NetworkManager.ForceFriendsSessionRefresh();
|
||||
|
||||
if (pClass->m_buttonListGames.getItemCount() > 0)
|
||||
{
|
||||
pClass->m_buttonListGames.setCurrentSelection(0);
|
||||
}
|
||||
|
||||
pClass->m_bPendingAddServerAddressKeyboard = false;
|
||||
pClass->m_bPendingAddServerAddressShowInvalid = false;
|
||||
pClass->m_bAddServerFlowActive = false;
|
||||
pClass->m_bIgnoreInput = false;
|
||||
pClass->UpdateGamesList();
|
||||
pClass->updateTooltips();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void UIScene_LoadOrJoinMenu::CheckAndJoinGame(int gameIndex)
|
||||
{
|
||||
if( m_buttonListGames.getItemCount() > 0 && gameIndex < m_currentSessions->size() )
|
||||
if( m_currentSessions != NULL && m_buttonListGames.getItemCount() > 0 && gameIndex >= 0 && gameIndex < (int)m_currentSessions->size() )
|
||||
{
|
||||
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
|
||||
// 4J-PB - is the player allowed to join games?
|
||||
|
|
@ -1610,10 +2049,24 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
|
|||
|
||||
|
||||
FriendSessionInfo *pSelectedSession = NULL;
|
||||
#ifdef _WINDOWS64
|
||||
bool addServerSelected = false;
|
||||
#endif
|
||||
if(DoesGamesListHaveFocus() && m_buttonListGames.getItemCount() > 0)
|
||||
{
|
||||
unsigned int nIndex = m_buttonListGames.getCurrentSelection();
|
||||
#ifdef _WINDOWS64
|
||||
if (IsAddServerListIndex((int)nIndex))
|
||||
{
|
||||
addServerSelected = true;
|
||||
}
|
||||
else if (m_currentSessions != NULL && nIndex < m_currentSessions->size())
|
||||
{
|
||||
pSelectedSession = m_currentSessions->at(nIndex);
|
||||
}
|
||||
#else
|
||||
pSelectedSession = m_currentSessions->at( nIndex );
|
||||
#endif
|
||||
}
|
||||
|
||||
SessionID selectedSessionId;
|
||||
|
|
@ -1665,6 +2118,9 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
|
|||
|
||||
// clear out the games list and re-fill
|
||||
m_buttonListGames.clearList();
|
||||
#ifdef _WINDOWS64
|
||||
bool selectedSessionRestored = false;
|
||||
#endif
|
||||
|
||||
if( filteredListSize > 0 )
|
||||
{
|
||||
|
|
@ -1734,12 +2190,27 @@ void UIScene_LoadOrJoinMenu::UpdateGamesList()
|
|||
if(memcmp( &selectedSessionId, &sessionInfo->sessionId, sizeof(SessionID) ) == 0)
|
||||
{
|
||||
m_buttonListGames.setCurrentSelection(sessionIndex);
|
||||
#ifdef _WINDOWS64
|
||||
selectedSessionRestored = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
++sessionIndex;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
m_buttonListGames.addItem(L"Add Server...", L"");
|
||||
if (addServerSelected || (filteredListSize == 0 && m_buttonListGames.getItemCount() > 0))
|
||||
{
|
||||
m_buttonListGames.setCurrentSelection(m_buttonListGames.getItemCount() - 1);
|
||||
}
|
||||
else if (!selectedSessionRestored && filteredListSize > 0)
|
||||
{
|
||||
m_buttonListGames.setCurrentSelection(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
updateTooltips();
|
||||
}
|
||||
|
||||
|
|
@ -1893,7 +2364,12 @@ void UIScene_LoadOrJoinMenu::LoadSaveFromDisk(File *saveFile, ESavePlatform save
|
|||
|
||||
__int64 fileSize = saveFile->length();
|
||||
FileInputStream fis(*saveFile);
|
||||
byteArray ba(fileSize);
|
||||
if (fileSize < 0 || fileSize > 0xFFFFFFFF)
|
||||
{
|
||||
app.DebugPrintf("LoadSaveFromDisk failed: invalid file size %I64d\n", fileSize);
|
||||
return;
|
||||
}
|
||||
byteArray ba((unsigned int)fileSize);
|
||||
fis.read(ba);
|
||||
fis.close();
|
||||
|
||||
|
|
@ -2101,6 +2577,11 @@ int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JS
|
|||
#ifdef _DURANGO
|
||||
// bring up a keyboard
|
||||
InputManager.RequestKeyboard(app.GetString(IDS_RENAME_WORLD_TITLE), (pClass->m_saveDetails[pClass->m_iSaveListIndex-pClass->m_iDefaultButtonsC]).UTF16SaveName,(DWORD)0,25,&UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback,pClass,C_4JInput::EKeyboardMode_Default);
|
||||
#elif defined(_WINDOWS64)
|
||||
wchar_t wSaveName[128];
|
||||
ZeroMemory(wSaveName, 128 * sizeof(wchar_t) );
|
||||
mbstowcs(wSaveName, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, strlen(pClass->m_saveDetails->UTF8SaveName)+1);
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_RENAME_WORLD_TITLE), wSaveName, (DWORD)0, 25, &UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback, pClass, C_4JInput::EKeyboardMode_Default);
|
||||
#else
|
||||
// bring up a keyboard
|
||||
wchar_t wSaveName[128];
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ private:
|
|||
bool m_bSaveTransferCancelled;
|
||||
#endif
|
||||
bool m_bUpdateSaveSize;
|
||||
#ifdef _WINDOWS64
|
||||
wchar_t m_pendingServerName[64];
|
||||
bool m_bAddServerFlowActive;
|
||||
bool m_bPendingAddServerAddressKeyboard;
|
||||
bool m_bPendingAddServerAddressShowInvalid;
|
||||
wchar_t m_pendingServerAddressInput[128];
|
||||
#endif
|
||||
|
||||
public:
|
||||
UIScene_LoadOrJoinMenu(int iPad, void *initData, UILayer *parentLayer);
|
||||
|
|
@ -169,6 +176,16 @@ public:
|
|||
|
||||
private:
|
||||
void CheckAndJoinGame(int gameIndex);
|
||||
#ifdef _WINDOWS64
|
||||
void BeginAddServerFlow();
|
||||
void QueueAddServerAddressKeyboard(const wchar_t *initialText, bool showInvalidMessage = false);
|
||||
bool IsAddServerListIndex(int listIndex);
|
||||
bool TryGetSavedServerAtListIndex(int listIndex, char *pHost, int hostSize, unsigned short *pPort);
|
||||
bool CanRemoveSavedServerAtListIndex(int listIndex);
|
||||
bool RemoveSavedServerAtListIndex(int listIndex);
|
||||
static int AddServerNameKeyboardCallback(LPVOID lpParam, bool bRes);
|
||||
static int AddServerAddressKeyboardCallback(LPVOID lpParam, bool bRes);
|
||||
#endif
|
||||
#if defined(__PS3__) || defined(__PSVITA__) || defined(__ORBIS__)
|
||||
static int MustSignInReturnedPSN(void *pParam,int iPad,C4JStorage::EMessageResult result);
|
||||
static int PSN_SignInReturned(void *pParam,bool bContinue, int iPad);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,11 @@ int UIScene_SignEntryMenu::KeyboardCompleteCallback(LPVOID lpParam,bool bRes)
|
|||
{
|
||||
uint16_t pchText[128];
|
||||
ZeroMemory(pchText, 128 * sizeof(uint16_t) );
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::GetText(pchText);
|
||||
#else
|
||||
InputManager.GetText(pchText);
|
||||
#endif
|
||||
pchText[15] = 0;
|
||||
pClass->m_textInputLines[pClass->m_iEditingLine].setLabel((wchar_t *)pchText);
|
||||
}
|
||||
|
|
@ -173,7 +177,9 @@ void UIScene_SignEntryMenu::handlePress(F64 controlId, F64 childId)
|
|||
{
|
||||
m_iEditingLine = (int)controlId;
|
||||
m_bIgnoreInput = true;
|
||||
#ifdef _XBOX_ONE
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_SIGN_TITLE), m_textInputLines[m_iEditingLine].getLabel(), (DWORD)m_iPad, 15, &UIScene_SignEntryMenu::KeyboardCompleteCallback, this, C_4JInput::EKeyboardMode_Alphabet);
|
||||
#elif defined(_XBOX_ONE)
|
||||
// 4J-PB - Xbox One uses the Windows virtual keyboard, and doesn't have the Xbox 360 Latin keyboard type, so we can't restrict the input set to alphanumeric. The closest we get is the emailSmtpAddress type.
|
||||
int language = XGetLanguage();
|
||||
switch(language)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "XUI_Ctrl_4JEdit.h"
|
||||
#include "../UI/UIScene_Keyboard.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -159,7 +160,12 @@ HRESULT CXuiCtrl4JEdit::OnKeyDown(XUIMessageInput* pInputData, BOOL& rfHandled)
|
|||
|
||||
void CXuiCtrl4JEdit::RequestKeyboard(int iPad)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
const wchar_t *title = (m_uiTitle != 0) ? app.GetString(m_uiTitle) : L"";
|
||||
Win64InGameKeyboard::Request(title, GetText(), (unsigned int)iPad, m_uTextLimit, &CXuiCtrl4JEdit::KeyboardReturned, this, m_eKeyboardMode, wchText, m_uTextLimit + 1);
|
||||
#else
|
||||
InputManager.RequestKeyboard(m_uiTitle,GetText(),m_uiText,iPad,wchText,m_uTextLimit+1,&CXuiCtrl4JEdit::KeyboardReturned,this,m_eKeyboardMode,app.GetStringTable());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,43 @@ HRESULT CScene_FullscreenProgress::OnInit( XUIMessageInit* pInitData, BOOL& bHan
|
|||
HRESULT CScene_FullscreenProgress::OnDestroy()
|
||||
{
|
||||
if( thread != NULL && thread != INVALID_HANDLE_VALUE )
|
||||
delete thread;
|
||||
{
|
||||
if( !threadStarted )
|
||||
{
|
||||
delete thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
int code = thread->GetExitCode();
|
||||
DWORD exitcode = *((DWORD *)&code);
|
||||
|
||||
if( exitcode == STILL_ACTIVE && m_cancelFunc != NULL && !m_bWasCancelled )
|
||||
{
|
||||
m_bWasCancelled = true;
|
||||
m_cancelFunc(m_cancelFuncParam);
|
||||
}
|
||||
|
||||
if( exitcode == STILL_ACTIVE )
|
||||
{
|
||||
DWORD waitResult = thread->WaitForCompletion(5000);
|
||||
if( waitResult == WAIT_TIMEOUT )
|
||||
{
|
||||
app.DebugPrintf("XUI_FullscreenProgress: skipping active thread delete to avoid shutdown race\n");
|
||||
thread = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_CompletionData != NULL )
|
||||
delete m_CompletionData;
|
||||
|
|
|
|||
|
|
@ -888,6 +888,7 @@ void CScene_MultiGameCreate::CreateGame(CScene_MultiGameCreate* pClass, DWORD dw
|
|||
StorageManager.ResetSaveData();
|
||||
// Make our next save default to the name of the level
|
||||
StorageManager.SetSaveTitle((wchar_t *)wWorldName.c_str());
|
||||
MinecraftServer::SetDeleteOnNoSaveForCurrentSession(true);
|
||||
|
||||
BOOL bHasSeed = (pClass->m_EditSeed.GetText() != NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#define UPDATE_PLAYERS_TIMER_ID 0
|
||||
#define UPDATE_PLAYERS_TIMER_TIME 30000
|
||||
#define CONNECT_POLL_TIMER_ID 1
|
||||
#define CONNECT_POLL_TIMER_TIME 100
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Performs initialization tasks - retrieves controls.
|
||||
|
|
@ -317,10 +319,14 @@ void CScene_MultiGameInfo::JoinGame(CScene_MultiGameInfo* pClass)
|
|||
{
|
||||
CGameNetworkManager::eJoinGameResult result = g_NetworkManager.JoinGame( pClass->m_selectedSession, dwLocalUsersMask );
|
||||
|
||||
// Alert the app the we no longer want to be informed of ethernet connections
|
||||
app.SetLiveLinkRequired( false );
|
||||
|
||||
if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||
if( result == CGameNetworkManager::JOINGAME_PENDING )
|
||||
{
|
||||
pClass->m_bIgnoreInput = true;
|
||||
pClass->SetTimer(CONNECT_POLL_TIMER_ID, CONNECT_POLL_TIMER_TIME);
|
||||
}
|
||||
else if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||
{
|
||||
int exitReasonStringId = -1;
|
||||
switch(result)
|
||||
|
|
@ -349,7 +355,24 @@ void CScene_MultiGameInfo::JoinGame(CScene_MultiGameInfo* pClass)
|
|||
|
||||
HRESULT CScene_MultiGameInfo::OnTimer( XUIMessageTimer *pTimer, BOOL& bHandled )
|
||||
{
|
||||
if ( pTimer->nId == UPDATE_PLAYERS_TIMER_ID)
|
||||
if ( pTimer->nId == CONNECT_POLL_TIMER_ID)
|
||||
{
|
||||
KillTimer(CONNECT_POLL_TIMER_ID);
|
||||
if (g_NetworkManager.IsJoinPending())
|
||||
{
|
||||
SetTimer(CONNECT_POLL_TIMER_ID, CONNECT_POLL_TIMER_TIME);
|
||||
}
|
||||
else if (!g_NetworkManager.IsInSession())
|
||||
{
|
||||
m_bIgnoreInput = false;
|
||||
SetShow(TRUE);
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0] = IDS_CONFIRM_OK;
|
||||
StorageManager.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable());
|
||||
app.NavigateBack(ProfileManager.GetPrimaryPad());
|
||||
}
|
||||
}
|
||||
else if ( pTimer->nId == UPDATE_PLAYERS_TIMER_ID)
|
||||
{
|
||||
PlayerUID selectedPlayerXUID = m_selectedSession->data.players[playersList.GetCurSel()];
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "XUI_MultiGameCreate.h"
|
||||
#include "../../MinecraftServer.h"
|
||||
#include "../../Options.h"
|
||||
#include "../UI/UIScene_Keyboard.h"
|
||||
|
||||
#include "../GameRules/LevelGenerationOptions.h"
|
||||
#include "../../TexturePackRepository.h"
|
||||
|
|
@ -2241,7 +2242,11 @@ int CScene_MultiGameJoinLoad::SaveOptionsDialogReturned(void *pParam,int iPad,C4
|
|||
{
|
||||
ZeroMemory(pClass->m_wchNewName,sizeof(WCHAR)*XCONTENT_MAX_DISPLAYNAME_LENGTH);
|
||||
// bring up a keyboard
|
||||
#ifdef _WINDOWS64
|
||||
Win64InGameKeyboard::Request(app.GetString(IDS_RENAME_WORLD_TITLE), L"", (unsigned int)iPad, XCONTENT_MAX_DISPLAYNAME_LENGTH - 1, &CScene_MultiGameJoinLoad::KeyboardReturned, pClass, C_4JInput::EKeyboardMode_Default, pClass->m_wchNewName, XCONTENT_MAX_DISPLAYNAME_LENGTH);
|
||||
#else
|
||||
InputManager.RequestKeyboard(IDS_RENAME_WORLD_TITLE,L"",IDS_RENAME_WORLD_TEXT,iPad,pClass->m_wchNewName,XCONTENT_MAX_DISPLAYNAME_LENGTH,&CScene_MultiGameJoinLoad::KeyboardReturned,pClass,C_4JInput::EKeyboardMode_Default,app.GetStringTable());
|
||||
#endif
|
||||
}
|
||||
else // delete
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
//#include <compressapi.h>
|
||||
#endif // __PS3__
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef __PS3__
|
||||
#include "PS3/Sentient/SentientManager.h"
|
||||
#include "StatsCounter.h"
|
||||
|
|
@ -190,6 +196,26 @@ D3DXVECTOR3& D3DXVECTOR3::operator += ( CONST D3DXVECTOR3& add ) { x += add.x; y
|
|||
|
||||
#include "Windows64/Network/WinsockNetLayer.h"
|
||||
|
||||
static const DWORD WIN64_QNET_DEFAULT_CAPACITY = MINECRAFT_NET_MAX_PLAYERS;
|
||||
static const DWORD WIN64_QNET_MAX_CAPACITY = 255;
|
||||
|
||||
static DWORD Win64_ClampQNetCapacity(DWORD capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
capacity = 1;
|
||||
if (capacity > WIN64_QNET_MAX_CAPACITY)
|
||||
capacity = WIN64_QNET_MAX_CAPACITY;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
static void Win64_EnsureQNetStorage()
|
||||
{
|
||||
if (IQNet::m_player == NULL || IQNet::s_playerCapacity == 0)
|
||||
{
|
||||
IQNet::SetPlayerCapacity(WIN64_QNET_DEFAULT_CAPACITY);
|
||||
}
|
||||
}
|
||||
|
||||
BYTE IQNetPlayer::GetSmallId() { return m_smallId; }
|
||||
void IQNetPlayer::SendData(IQNetPlayer *player, const void *pvData, DWORD dwDataSize, DWORD dwFlags)
|
||||
{
|
||||
|
|
@ -209,6 +235,7 @@ static void Win64_BuildSplitName(int iPad, char *outName, int outSize);
|
|||
PlayerUID IQNetPlayer::GetXuid()
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
Win64_EnsureQNetStorage();
|
||||
if (!m_isRemote)
|
||||
{
|
||||
int idx = (int)(this - &IQNet::m_player[0]);
|
||||
|
|
@ -230,6 +257,7 @@ PlayerUID IQNetPlayer::GetXuid()
|
|||
|
||||
PlayerUID Win64_UsernameToXuid(const char* username)
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
uint64_t hash = 14695981039346656037ULL;
|
||||
for (const char* p = username; *p; ++p)
|
||||
{
|
||||
|
|
@ -238,8 +266,9 @@ PlayerUID Win64_UsernameToXuid(const char* username)
|
|||
}
|
||||
|
||||
const uint64_t WIN64_XUID_BASE = 0xe000d45248242f2e;
|
||||
if (hash >= WIN64_XUID_BASE && hash <= WIN64_XUID_BASE + MINECRAFT_NET_MAX_PLAYERS)
|
||||
hash = WIN64_XUID_BASE + MINECRAFT_NET_MAX_PLAYERS + 1;
|
||||
uint64_t reservedRange = IQNet::GetPlayerCapacity();
|
||||
if (hash >= WIN64_XUID_BASE && hash <= WIN64_XUID_BASE + reservedRange)
|
||||
hash = WIN64_XUID_BASE + reservedRange + 1;
|
||||
if (hash == 0)
|
||||
hash = 1;
|
||||
return (PlayerUID)hash;
|
||||
|
|
@ -257,10 +286,12 @@ PlayerUID Win64_UsernameToXuid(const wchar_t* username)
|
|||
|
||||
static void Win64_BuildSplitName(int iPad, char *outName, int outSize)
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
extern char g_Win64Username[17];
|
||||
char candidate[32];
|
||||
sprintf_s(candidate, sizeof(candidate), "%s_%d", g_Win64Username, iPad);
|
||||
for (DWORD i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
DWORD capacity = IQNet::GetPlayerCapacity();
|
||||
for (DWORD i = 0; i < capacity; i++)
|
||||
{
|
||||
if (!IQNet::m_player[i].m_isRemote) continue;
|
||||
if (IQNet::m_player[i].m_gamertag[0] == 0) continue;
|
||||
|
|
@ -307,7 +338,10 @@ bool IQNetPlayer::HasVoice() {
|
|||
#endif
|
||||
}
|
||||
bool IQNetPlayer::HasCamera() { return false; }
|
||||
int IQNetPlayer::GetUserIndex() { return this - &IQNet::m_player[0]; }
|
||||
int IQNetPlayer::GetUserIndex() {
|
||||
Win64_EnsureQNetStorage();
|
||||
return (int)(this - &IQNet::m_player[0]);
|
||||
}
|
||||
void IQNetPlayer::SetCustomDataValue(ULONG_PTR ulpCustomDataValue) {
|
||||
m_customData = ulpCustomDataValue;
|
||||
}
|
||||
|
|
@ -315,10 +349,77 @@ ULONG_PTR IQNetPlayer::GetCustomDataValue() {
|
|||
return m_customData;
|
||||
}
|
||||
|
||||
IQNetPlayer IQNet::m_player[MINECRAFT_NET_MAX_PLAYERS];
|
||||
IQNetPlayer *IQNet::m_player = NULL;
|
||||
DWORD IQNet::s_playerCapacity = 0;
|
||||
DWORD IQNet::s_playerCount = 1;
|
||||
bool IQNet::s_isHosting = true;
|
||||
|
||||
void IQNet::SetPlayerCapacity(DWORD capacity)
|
||||
{
|
||||
DWORD newCapacity = Win64_ClampQNetCapacity(capacity);
|
||||
if (m_player != NULL && s_playerCapacity == newCapacity)
|
||||
{
|
||||
if (s_playerCount > s_playerCapacity)
|
||||
s_playerCount = s_playerCapacity;
|
||||
if (s_playerCount == 0)
|
||||
s_playerCount = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
IQNetPlayer *newPlayers = new IQNetPlayer[newCapacity];
|
||||
for (DWORD i = 0; i < newCapacity; ++i)
|
||||
{
|
||||
newPlayers[i].m_smallId = (BYTE)i;
|
||||
newPlayers[i].m_isRemote = false;
|
||||
newPlayers[i].m_isHostPlayer = false;
|
||||
newPlayers[i].m_gamertag[0] = 0;
|
||||
newPlayers[i].SetCustomDataValue(0);
|
||||
}
|
||||
|
||||
if (m_player != NULL)
|
||||
{
|
||||
DWORD copyCount = (s_playerCapacity < newCapacity) ? s_playerCapacity : newCapacity;
|
||||
for (DWORD i = 0; i < copyCount; ++i)
|
||||
{
|
||||
newPlayers[i] = m_player[i];
|
||||
}
|
||||
delete [] m_player;
|
||||
}
|
||||
|
||||
m_player = newPlayers;
|
||||
s_playerCapacity = newCapacity;
|
||||
if (s_playerCount > s_playerCapacity)
|
||||
s_playerCount = s_playerCapacity;
|
||||
if (s_playerCount == 0)
|
||||
s_playerCount = 1;
|
||||
}
|
||||
|
||||
DWORD IQNet::GetPlayerCapacity()
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
return s_playerCapacity;
|
||||
}
|
||||
|
||||
struct IQNetStorageBootstrap
|
||||
{
|
||||
IQNetStorageBootstrap()
|
||||
{
|
||||
IQNet::SetPlayerCapacity(WIN64_QNET_DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
~IQNetStorageBootstrap()
|
||||
{
|
||||
if (IQNet::m_player != NULL)
|
||||
{
|
||||
delete [] IQNet::m_player;
|
||||
IQNet::m_player = NULL;
|
||||
}
|
||||
IQNet::s_playerCapacity = 0;
|
||||
}
|
||||
};
|
||||
|
||||
static IQNetStorageBootstrap g_iqNetStorageBootstrap;
|
||||
|
||||
QNET_STATE _iQNetStubState = QNET_STATE_IDLE;
|
||||
|
||||
bool g_connectedToDedicatedServer = false;
|
||||
|
|
@ -337,7 +438,11 @@ static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index);
|
|||
|
||||
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex)
|
||||
{
|
||||
if (dwUserIndex >= MINECRAFT_NET_MAX_PLAYERS) return E_FAIL;
|
||||
Win64_EnsureQNetStorage();
|
||||
if (dwUserIndex >= GetPlayerCapacity())
|
||||
SetPlayerCapacity(dwUserIndex + 1);
|
||||
if (dwUserIndex >= GetPlayerCapacity())
|
||||
return E_FAIL;
|
||||
m_player[dwUserIndex].m_isRemote = false;
|
||||
m_player[dwUserIndex].m_smallId = (BYTE)dwUserIndex;
|
||||
if (dwUserIndex > 0)
|
||||
|
|
@ -350,12 +455,16 @@ HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex)
|
|||
s_playerCount = dwUserIndex + 1;
|
||||
return S_OK;
|
||||
}
|
||||
IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; }
|
||||
IQNetPlayer *IQNet::GetHostPlayer() {
|
||||
Win64_EnsureQNetStorage();
|
||||
return &m_player[0];
|
||||
}
|
||||
IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
if (s_isHosting)
|
||||
{
|
||||
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS &&
|
||||
if (dwUserIndex < GetPlayerCapacity() &&
|
||||
!m_player[dwUserIndex].m_isRemote)
|
||||
return &m_player[dwUserIndex];
|
||||
return NULL;
|
||||
|
|
@ -384,6 +493,7 @@ static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index)
|
|||
|
||||
IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
DWORD found = 0;
|
||||
for (DWORD i = 0; i < s_playerCount; i++)
|
||||
{
|
||||
|
|
@ -397,7 +507,10 @@ IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
|
|||
}
|
||||
IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId)
|
||||
{
|
||||
if (SmallId >= MINECRAFT_NET_MAX_PLAYERS)
|
||||
Win64_EnsureQNetStorage();
|
||||
if (SmallId >= GetPlayerCapacity())
|
||||
SetPlayerCapacity((DWORD)SmallId + 1);
|
||||
if (SmallId >= GetPlayerCapacity())
|
||||
return NULL;
|
||||
|
||||
m_player[SmallId].m_smallId = SmallId;
|
||||
|
|
@ -407,7 +520,9 @@ IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId)
|
|||
}
|
||||
IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid)
|
||||
{
|
||||
for (DWORD i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
Win64_EnsureQNetStorage();
|
||||
DWORD capacity = GetPlayerCapacity();
|
||||
for (DWORD i = 0; i < capacity; i++)
|
||||
{
|
||||
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
|
||||
}
|
||||
|
|
@ -415,6 +530,7 @@ IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid)
|
|||
}
|
||||
DWORD IQNet::GetPlayerCount()
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
DWORD count = 0;
|
||||
for (DWORD i = 0; i < s_playerCount; i++)
|
||||
{
|
||||
|
|
@ -428,10 +544,12 @@ HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const
|
|||
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
|
||||
void IQNet::ClientJoinGame()
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
_iQNetStubState = QNET_STATE_SESSION_STARTING;
|
||||
s_isHosting = false;
|
||||
|
||||
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
DWORD capacity = GetPlayerCapacity();
|
||||
for (DWORD i = 0; i < capacity; i++)
|
||||
{
|
||||
m_player[i].m_smallId = (BYTE)i;
|
||||
m_player[i].m_isRemote = true;
|
||||
|
|
@ -442,10 +560,12 @@ void IQNet::ClientJoinGame()
|
|||
}
|
||||
void IQNet::EndGame()
|
||||
{
|
||||
Win64_EnsureQNetStorage();
|
||||
_iQNetStubState = QNET_STATE_IDLE;
|
||||
s_isHosting = false;
|
||||
s_playerCount = 1;
|
||||
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||
DWORD capacity = GetPlayerCapacity();
|
||||
for (DWORD i = 0; i < capacity; i++)
|
||||
{
|
||||
m_player[i].m_smallId = (BYTE)i;
|
||||
m_player[i].m_isRemote = false;
|
||||
|
|
@ -619,20 +739,90 @@ bool Win64_HasSavedProfile(int iPad)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void GetProfileRootPath(char *outPath, int maxLen)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
char curDir[256] = {0};
|
||||
if (getcwd(curDir, sizeof(curDir)) == NULL)
|
||||
{
|
||||
outPath[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
char win64Path[256] = {0};
|
||||
snprintf(win64Path, sizeof(win64Path), "%s/Windows64", curDir);
|
||||
mkdir(win64Path, 0755);
|
||||
snprintf(outPath, maxLen, "%s/Windows64/GameHDD", curDir);
|
||||
mkdir(outPath, 0755);
|
||||
return;
|
||||
#else
|
||||
char exePath[MAX_PATH] = {0};
|
||||
DWORD exeLen = GetModuleFileNameA(NULL, exePath, MAX_PATH);
|
||||
if (exeLen > 0 && exeLen < MAX_PATH)
|
||||
{
|
||||
char *lastSlash = strrchr(exePath, '\\');
|
||||
if (lastSlash != NULL)
|
||||
{
|
||||
*lastSlash = '\0';
|
||||
char win64Path[MAX_PATH] = {0};
|
||||
sprintf_s(win64Path, sizeof(win64Path), "%s\\Windows64", exePath);
|
||||
CreateDirectoryA(win64Path, 0);
|
||||
sprintf_s(outPath, maxLen, "%s\\Windows64\\GameHDD", exePath);
|
||||
CreateDirectoryA(outPath, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char curDir[256] = {0};
|
||||
GetCurrentDirectoryA(sizeof(curDir), curDir);
|
||||
char win64Path[256] = {0};
|
||||
sprintf_s(win64Path, sizeof(win64Path), "%s\\Windows64", curDir);
|
||||
CreateDirectoryA(win64Path, 0);
|
||||
sprintf_s(outPath, maxLen, "%s\\Windows64\\GameHDD", curDir);
|
||||
CreateDirectoryA(outPath, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void GetProfileFilePath(int iQuadrant, char *outPath, int maxLen)
|
||||
{
|
||||
char curDir[256];
|
||||
char rootPath[MAX_PATH] = {0};
|
||||
GetProfileRootPath(rootPath, sizeof(rootPath));
|
||||
#if defined(__linux__)
|
||||
snprintf(outPath, maxLen, "%s/profile_%d.dat", rootPath, iQuadrant);
|
||||
#else
|
||||
sprintf_s(outPath, maxLen, "%s\\profile_%d.dat", rootPath, iQuadrant);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void GetLegacyProfileFilePath(int iQuadrant, char *outPath, int maxLen)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
char curDir[256] = {0};
|
||||
if (getcwd(curDir, sizeof(curDir)) == NULL)
|
||||
{
|
||||
outPath[0] = 0;
|
||||
return;
|
||||
}
|
||||
snprintf(outPath, maxLen, "%s/Windows64/GameHDD/profile_%d.dat", curDir, iQuadrant);
|
||||
#else
|
||||
char curDir[256] = {0};
|
||||
GetCurrentDirectoryA(sizeof(curDir), curDir);
|
||||
sprintf_s(outPath, maxLen, "%s\\Windows64\\GameHDD\\profile_%d.dat", curDir, iQuadrant);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool LoadProfileFromDisk(int iQuadrant, void *pData, int dataSize)
|
||||
{
|
||||
char path[256];
|
||||
char path[MAX_PATH] = {0};
|
||||
GetProfileFilePath(iQuadrant, path, sizeof(path));
|
||||
FILE *f = NULL;
|
||||
fopen_s(&f, path, "rb");
|
||||
if (!f) return false;
|
||||
if (!f)
|
||||
{
|
||||
GetLegacyProfileFilePath(iQuadrant, path, sizeof(path));
|
||||
fopen_s(&f, path, "rb");
|
||||
if (!f) return false;
|
||||
}
|
||||
size_t bytesRead = fread(pData, 1, dataSize, f);
|
||||
fclose(f);
|
||||
return (bytesRead == (size_t)dataSize);
|
||||
|
|
@ -640,7 +830,7 @@ static bool LoadProfileFromDisk(int iQuadrant, void *pData, int dataSize)
|
|||
|
||||
static void SaveProfileToDisk(int iQuadrant, void *pData, int dataSize)
|
||||
{
|
||||
char path[256];
|
||||
char path[MAX_PATH] = {0};
|
||||
GetProfileFilePath(iQuadrant, path, sizeof(path));
|
||||
FILE *f = NULL;
|
||||
fopen_s(&f, path, "wb");
|
||||
|
|
|
|||
|
|
@ -62,6 +62,14 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
|||
int splitYOffset;// = 20; // This offset is applied when doing the 2X scaling above to move the gui out of the way of the tool tips
|
||||
int guiScale;// = ( minecraft->player->m_iScreenSection == C4JRender::VIEWPORT_TYPE_FULLSCREEN ? 3 : 2 );
|
||||
int iPad=minecraft->player->GetXboxPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
iPad = 0;
|
||||
}
|
||||
}
|
||||
int iWidthOffset=0,iHeightOffset=0; // used to get the interface looking right on a 2 player split screen game
|
||||
|
||||
// 4J-PB - selected the gui scale based on the slider settings
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "KeyboardMouseInput.h"
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
#include "Windows64/KBMConfig.h"
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
KeyboardMouseInput g_KBMInput;
|
||||
|
|
@ -14,6 +16,7 @@ int KeyboardMouseInput::KEY_SNEAK = VK_LSHIFT;
|
|||
int KeyboardMouseInput::KEY_SPRINT = VK_LCONTROL;
|
||||
int KeyboardMouseInput::KEY_INVENTORY = 'E';
|
||||
int KeyboardMouseInput::KEY_DROP = 'Q';
|
||||
int KeyboardMouseInput::KEY_CHAT = 'T';
|
||||
int KeyboardMouseInput::KEY_CRAFTING = VK_TAB;
|
||||
int KeyboardMouseInput::KEY_CONFIRM = VK_RETURN;
|
||||
int KeyboardMouseInput::KEY_PAUSE = VK_ESCAPE;
|
||||
|
|
@ -29,6 +32,26 @@ static void ClipCursorToWindow(HWND hWnd);
|
|||
// coded by notpies fr
|
||||
void KeyboardMouseInput::Init()
|
||||
{
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
KBMConfig& cfg = KBMConfig::Get();
|
||||
KeyboardMouseInput::KEY_FORWARD = cfg.keyForward;
|
||||
KeyboardMouseInput::KEY_BACKWARD = cfg.keyBackward;
|
||||
KeyboardMouseInput::KEY_LEFT = cfg.keyLeft;
|
||||
KeyboardMouseInput::KEY_RIGHT = cfg.keyRight;
|
||||
KeyboardMouseInput::KEY_JUMP = cfg.keyJump;
|
||||
KeyboardMouseInput::KEY_SNEAK = cfg.keySneak;
|
||||
KeyboardMouseInput::KEY_SPRINT = cfg.keySprint;
|
||||
KeyboardMouseInput::KEY_INVENTORY = cfg.keyInventory;
|
||||
KeyboardMouseInput::KEY_DROP = cfg.keyDrop;
|
||||
KeyboardMouseInput::KEY_CHAT = cfg.keyChat;
|
||||
KeyboardMouseInput::KEY_CRAFTING = cfg.keyCrafting;
|
||||
KeyboardMouseInput::KEY_CONFIRM = cfg.keyConfirm;
|
||||
KeyboardMouseInput::KEY_PAUSE = cfg.keyPause;
|
||||
KeyboardMouseInput::KEY_THIRD_PERSON = cfg.keyThirdPerson;
|
||||
KeyboardMouseInput::KEY_DEBUG_INFO = cfg.keyDebugInfo;
|
||||
KeyboardMouseInput::KEY_VOICE = cfg.keyVoice;
|
||||
#endif
|
||||
|
||||
memset(m_keyDown, 0, sizeof(m_keyDown));
|
||||
memset(m_keyDownPrev, 0, sizeof(m_keyDownPrev));
|
||||
memset(m_keyPressedAccum, 0, sizeof(m_keyPressedAccum));
|
||||
|
|
@ -49,6 +72,7 @@ void KeyboardMouseInput::Init()
|
|||
m_mouseDeltaAccumY = 0;
|
||||
m_mouseWheel = 0;
|
||||
m_mouseWheelAccum = 0;
|
||||
m_mouseWheelRemainder = 0;
|
||||
m_mouseGrabbed = false;
|
||||
m_cursorHiddenForUI = false;
|
||||
m_windowFocused = true;
|
||||
|
|
@ -86,6 +110,7 @@ void KeyboardMouseInput::ClearAllState()
|
|||
m_mouseDeltaAccumY = 0;
|
||||
m_mouseWheel = 0;
|
||||
m_mouseWheelAccum = 0;
|
||||
m_mouseWheelRemainder = 0;
|
||||
m_hadRawMouseInput = false;
|
||||
}
|
||||
|
||||
|
|
@ -109,10 +134,14 @@ void KeyboardMouseInput::Tick()
|
|||
m_mouseDeltaAccumX = 0;
|
||||
m_mouseDeltaAccumY = 0;
|
||||
|
||||
m_mouseWheel = m_mouseWheelAccum;
|
||||
m_mouseWheelAccum = 0;
|
||||
|
||||
m_hasInput = (m_mouseDeltaX != 0 || m_mouseDeltaY != 0 || m_mouseWheel != 0 || m_hadRawMouseInput);
|
||||
int wheelTotal = m_mouseWheelRemainder + m_mouseWheelAccum;
|
||||
int wheelSteps = wheelTotal / WHEEL_DELTA;
|
||||
m_mouseWheelRemainder = wheelTotal - (wheelSteps * WHEEL_DELTA);
|
||||
m_mouseWheelAccum = 0;
|
||||
m_mouseWheel += wheelSteps;
|
||||
|
||||
m_hasInput = (m_mouseDeltaX != 0 || m_mouseDeltaY != 0 || wheelSteps != 0 || m_hadRawMouseInput);
|
||||
m_hadRawMouseInput = false;
|
||||
if (!m_hasInput)
|
||||
{
|
||||
|
|
@ -268,6 +297,10 @@ void KeyboardMouseInput::SetMouseGrabbed(bool grabbed)
|
|||
while (ShowCursor(TRUE) < 0) {}
|
||||
ClipCursor(NULL);
|
||||
}
|
||||
|
||||
m_mouseWheel = 0;
|
||||
m_mouseWheelAccum = 0;
|
||||
m_mouseWheelRemainder = 0;
|
||||
}
|
||||
|
||||
void KeyboardMouseInput::SetCursorHiddenForUI(bool hidden)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ public:
|
|||
static int KEY_SPRINT;
|
||||
static int KEY_INVENTORY;
|
||||
static int KEY_DROP;
|
||||
static int KEY_CHAT;
|
||||
static int KEY_CRAFTING;
|
||||
static const int KEY_CRAFTING_ALT = 'R';
|
||||
static int KEY_CONFIRM;
|
||||
|
|
@ -59,6 +60,7 @@ public:
|
|||
bool HadRawMouseInput() const { return m_hadRawMouseInput; }
|
||||
|
||||
int GetMouseWheel() const { return m_mouseWheel; }
|
||||
int ConsumeMouseWheel() { int wheel = m_mouseWheel; m_mouseWheel = 0; return wheel; }
|
||||
|
||||
void SetMouseGrabbed(bool grabbed);
|
||||
bool IsMouseGrabbed() const { return m_mouseGrabbed; }
|
||||
|
|
@ -114,6 +116,7 @@ private:
|
|||
|
||||
int m_mouseWheel;
|
||||
int m_mouseWheelAccum;
|
||||
int m_mouseWheelRemainder;
|
||||
|
||||
bool m_mouseGrabbed;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ Chunk LevelRenderer::permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS];
|
|||
C4JThread *LevelRenderer::rebuildThreads[MAX_CHUNK_REBUILD_THREADS];
|
||||
C4JThread::EventArray *LevelRenderer::s_rebuildCompleteEvents;
|
||||
C4JThread::Event *LevelRenderer::s_activationEventA[MAX_CHUNK_REBUILD_THREADS];
|
||||
volatile bool LevelRenderer::s_rebuildThreadsTerminate = false;
|
||||
|
||||
// This defines the maximum size of renderable level, must be big enough to cope with actual size of level + view distance at each side
|
||||
// so that we can render the "infinite" sea at the edges. Currently defined as:
|
||||
|
|
@ -3589,6 +3590,12 @@ void LevelRenderer::DestroyedTileManager::tick()
|
|||
#ifdef _LARGE_WORLDS
|
||||
void LevelRenderer::staticCtor()
|
||||
{
|
||||
if (s_rebuildCompleteEvents != NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_rebuildThreadsTerminate = false;
|
||||
s_rebuildCompleteEvents = new C4JThread::EventArray(MAX_CHUNK_REBUILD_THREADS);
|
||||
char threadName[256];
|
||||
for(unsigned int i = 0; i < MAX_CHUNK_REBUILD_THREADS; ++i)
|
||||
|
|
@ -3614,6 +3621,46 @@ void LevelRenderer::staticCtor()
|
|||
}
|
||||
}
|
||||
|
||||
void LevelRenderer::shutdownRebuildThreads()
|
||||
{
|
||||
if (s_rebuildCompleteEvents == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_rebuildThreadsTerminate = true;
|
||||
|
||||
for (unsigned int i = 0; i < MAX_CHUNK_REBUILD_THREADS; ++i)
|
||||
{
|
||||
if (s_activationEventA[i] != NULL)
|
||||
{
|
||||
s_activationEventA[i]->Set();
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < MAX_CHUNK_REBUILD_THREADS; ++i)
|
||||
{
|
||||
if (rebuildThreads[i] != NULL)
|
||||
{
|
||||
rebuildThreads[i]->WaitForCompletion(INFINITE);
|
||||
delete rebuildThreads[i];
|
||||
rebuildThreads[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < MAX_CHUNK_REBUILD_THREADS; ++i)
|
||||
{
|
||||
if (s_activationEventA[i] != NULL)
|
||||
{
|
||||
delete s_activationEventA[i];
|
||||
s_activationEventA[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
delete s_rebuildCompleteEvents;
|
||||
s_rebuildCompleteEvents = NULL;
|
||||
}
|
||||
|
||||
int LevelRenderer::rebuildChunkThreadProc(LPVOID lpParam)
|
||||
{
|
||||
Vec3::CreateNewThreadStorage();
|
||||
|
|
@ -3630,6 +3677,11 @@ int LevelRenderer::rebuildChunkThreadProc(LPVOID lpParam)
|
|||
{
|
||||
s_activationEventA[index]->WaitForSignal(INFINITE);
|
||||
|
||||
if (s_rebuildThreadsTerminate)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//app.DebugPrintf("Rebuilding permaChunk %d\n", index + 1);
|
||||
permaChunk[index + 1].rebuild();
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,9 @@ public:
|
|||
static C4JThread *rebuildThreads[MAX_CHUNK_REBUILD_THREADS];
|
||||
static C4JThread::EventArray *s_rebuildCompleteEvents;
|
||||
static C4JThread::Event *s_activationEventA[MAX_CHUNK_REBUILD_THREADS];
|
||||
static volatile bool s_rebuildThreadsTerminate;
|
||||
static void staticCtor();
|
||||
static void shutdownRebuildThreads();
|
||||
static int rebuildChunkThreadProc(LPVOID lpParam);
|
||||
|
||||
CRITICAL_SECTION m_csChunkFlags;
|
||||
|
|
|
|||
|
|
@ -757,11 +757,17 @@ void LocalPlayer::awardStat(Stat *stat, byteArray param)
|
|||
int count = CommonStats::readParam(param);
|
||||
delete [] param.data;
|
||||
|
||||
if (!app.CanRecordStatsAndAchievements()) return;
|
||||
if (stat == NULL) return;
|
||||
if (stat == NULL) return;
|
||||
|
||||
const bool canRecordStatsAndAchievements = app.CanRecordStatsAndAchievements();
|
||||
|
||||
if (stat->isAchievement())
|
||||
{
|
||||
if (!canRecordStatsAndAchievements)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Achievement *ach = (Achievement *) stat;
|
||||
// 4J-PB - changed to attempt to award everytime - the award may need a storage device, so needs a primary player, and the player may not have been a primary player when they first 'got' the award
|
||||
// so let the award manager figure it out
|
||||
|
|
@ -804,6 +810,11 @@ void LocalPlayer::awardStat(Stat *stat, byteArray param)
|
|||
StatsCounter* pStats = minecraft->stats[m_iPad];
|
||||
pStats->award(stat, level->difficulty, count);
|
||||
|
||||
if (!canRecordStatsAndAchievements)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 4J-JEV: Check achievements for unlocks.
|
||||
|
||||
// LEADER OF THE PACK
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@
|
|||
<SccProvider>SAK</SccProvider>
|
||||
<Keyword>Xbox360Proj</Keyword>
|
||||
<ApplicationEnvironment>title</ApplicationEnvironment>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Platform)'=='x64'">10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'" Label="Configuration">
|
||||
|
|
@ -1293,7 +1294,7 @@ if not exist "$(TargetDir)\savedata" mkdir "$(TargetDir)\savedata"</Command>
|
|||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;..\Minecraft.World\x64_Debug\Minecraft.World.lib;%(AdditionalDependencies);XInput9_1_0.lib;..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>d3d11.lib;..\Minecraft.World\x64_Debug\Minecraft.World.lib;%(AdditionalDependencies);XInput9_1_0.lib;..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
</Link>
|
||||
|
|
@ -1432,7 +1433,7 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
|
|||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>d3d11.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
</Link>
|
||||
|
|
@ -1484,7 +1485,7 @@ copy /Y "$(ProjectDir)Durango\Sound\Minecraft.msscmp" "$(OutDir)Durango\Sound\"<
|
|||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>d3d11.lib;..\Minecraft.World\x64_Release\Minecraft.World.lib;XInput9_1_0.lib;Windows64\Iggy\lib\iggy_w64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<SuppressStartupBanner>false</SuppressStartupBanner>
|
||||
</Link>
|
||||
|
|
@ -25665,6 +25666,15 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">false</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Minecraft.Server\Core\ServerThreadPool.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">false</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Minimap.cpp" />
|
||||
<ClCompile Include="MobRenderer.cpp" />
|
||||
<ClCompile Include="MobSkinMemTextureProcessor.cpp" />
|
||||
|
|
@ -38325,17 +38335,17 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
|
||||
</Object>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(Platform)'=='Durango'">
|
||||
<SDKReference Include="Xbox GameChat API, Version=8.0" />
|
||||
<SDKReference Include="Xbox Services API, Version=8.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(Platform)'=='Durango'">
|
||||
<Reference Include="windows.xbox.networking.realtimesession">
|
||||
<HintPath>Durango\Network\windows.xbox.networking.realtimesession.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(Platform)'=='Durango'">
|
||||
<AppxManifest Include="Durango\Autogenerated.appxmanifest" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
|||
|
|
@ -4104,6 +4104,9 @@
|
|||
<ClCompile Include="MinecraftServer.cpp">
|
||||
<Filter>net\minecraft\server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Minecraft.Server\Core\ServerThreadPool.cpp">
|
||||
<Filter>net\minecraft\server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ServerChunkCache.cpp">
|
||||
<Filter>net\minecraft\server\level</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
#include "ErrorScreen.h"
|
||||
#include "TitleScreen.h"
|
||||
#include "InventoryScreen.h"
|
||||
#if !defined(_DEDICATED_SERVER)
|
||||
#include "ChatScreen.h"
|
||||
#endif
|
||||
#include "InBedChatScreen.h"
|
||||
#include "AchievementPopup.h"
|
||||
#include "Input.h"
|
||||
|
|
@ -37,6 +40,9 @@
|
|||
#include "KeyboardMouseInput.h"
|
||||
#endif
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
#include "Common/UI/UIScene_Keyboard.h"
|
||||
#endif
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
#include "Windows64/Audio/VoiceChat.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -69,6 +75,7 @@
|
|||
#include "../Minecraft.World/SparseLightStorage.h"
|
||||
#include "../Minecraft.World/SparseDataStorage.h"
|
||||
#include "TextureManager.h"
|
||||
#include "../Minecraft.World/SharedConstants.h"
|
||||
#ifdef _XBOX
|
||||
#include "Xbox/Network/NetworkPlayerXbox.h"
|
||||
#endif
|
||||
|
|
@ -76,6 +83,96 @@
|
|||
#include "Common/UI/UIFontData.h"
|
||||
#include "DLCTexturePack.h"
|
||||
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
namespace
|
||||
{
|
||||
wstring TrimKBMChatMessage(const wstring &message)
|
||||
{
|
||||
size_t start = 0;
|
||||
while (start < message.length() && iswspace(message[start]))
|
||||
{
|
||||
++start;
|
||||
}
|
||||
|
||||
size_t end = message.length();
|
||||
while (end > start && iswspace(message[end - 1]))
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
return message.substr(start, end - start);
|
||||
}
|
||||
|
||||
bool IsTextChatEnabled(Minecraft *minecraft)
|
||||
{
|
||||
if (minecraft == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!minecraft->isClientSide())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return app.GetGameHostOption(eGameHostOption_ChatDisabled) == 0;
|
||||
}
|
||||
|
||||
int KBMChatKeyboardCompleteCallback(void *lpParam, const bool bRes)
|
||||
{
|
||||
Minecraft *minecraft = (Minecraft *)lpParam;
|
||||
if (minecraft == NULL || !bRes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IsTextChatEnabled(minecraft))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t ui16Text[SharedConstants::maxChatLength + 2];
|
||||
ZeroMemory(ui16Text, sizeof(ui16Text));
|
||||
Win64InGameKeyboard::GetText(ui16Text);
|
||||
|
||||
wstring chatMessage = TrimKBMChatMessage((wchar_t *)ui16Text);
|
||||
if (chatMessage.length() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!minecraft->handleClientSideCommand(chatMessage) && minecraft->player != NULL)
|
||||
{
|
||||
minecraft->player->chat(chatMessage);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OpenKBMChatKeyboard(Minecraft *minecraft)
|
||||
{
|
||||
if (minecraft == NULL || Win64InGameKeyboard::IsActive() || !IsTextChatEnabled(minecraft))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int iPad = 0;
|
||||
if (minecraft->player != NULL && minecraft->player->GetXboxPad() >= 0)
|
||||
{
|
||||
iPad = (unsigned int)minecraft->player->GetXboxPad();
|
||||
}
|
||||
|
||||
Win64InGameKeyboard::Request(L"Chat Message",
|
||||
L"",
|
||||
iPad,
|
||||
SharedConstants::maxChatLength,
|
||||
&KBMChatKeyboardCompleteCallback,
|
||||
minecraft,
|
||||
C_4JInput::EKeyboardMode_Default);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __ORBIS__
|
||||
#include "Orbis/Network/PsPlusUpsellWrapper_Orbis.h"
|
||||
#endif
|
||||
|
|
@ -1490,11 +1587,18 @@ void Minecraft::run_middle()
|
|||
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING) || g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CRAFTING_ALT))
|
||||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CRAFTING;
|
||||
|
||||
int wheel = g_KBMInput.GetMouseWheel();
|
||||
if (wheel > 0)
|
||||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RIGHT_SCROLL;
|
||||
else if (wheel < 0)
|
||||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_LEFT_SCROLL;
|
||||
#if defined(_WINDOWS64) && !defined(_DEDICATED_SERVER)
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CHAT))
|
||||
{
|
||||
if (isClientSide() && IsTextChatEnabled(this) && screen == NULL && !ui.GetMenuDisplayed(i) && g_KBMInput.IsMouseGrabbed())
|
||||
{
|
||||
if (localplayers[i]->isSleeping() && level != NULL && level->isClientSide)
|
||||
setScreen(new InBedChatScreen());
|
||||
else
|
||||
OpenKBMChatKeyboard(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int slot = 0; slot < 9; slot++)
|
||||
{
|
||||
|
|
@ -3276,11 +3380,10 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
|
|||
wheel = -1;
|
||||
}
|
||||
#ifdef _WINDOWS64
|
||||
if (iPad == 0 && wheel == 0 && g_KBMInput.IsKBMActive())
|
||||
if (iPad == 0 && wheel == 0 && g_KBMInput.IsKBMActive() && g_KBMInput.IsMouseGrabbed())
|
||||
{
|
||||
int mw = g_KBMInput.GetMouseWheel();
|
||||
if (mw > 0) wheel = -1;
|
||||
else if (mw < 0) wheel = 1;
|
||||
int mw = g_KBMInput.ConsumeMouseWheel();
|
||||
if (mw != 0) wheel = mw;
|
||||
}
|
||||
#endif
|
||||
if (wheel != 0)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@
|
|||
#include "GameRenderer.h"
|
||||
#ifdef _WINDOWS64
|
||||
#include "Windows64/Network/WinsockNetLayer.h"
|
||||
#elif defined(WITH_SERVER_CODE)
|
||||
#include "../Minecraft.Server/Linux/PosixNetLayer.h"
|
||||
#endif
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
#include "../Minecraft.Server/Core/ServerThreadPool.h"
|
||||
#endif
|
||||
#include "../Minecraft.World/ThreadName.h"
|
||||
#include "../Minecraft.World/IntCache.h"
|
||||
|
|
@ -69,6 +74,7 @@ __int64 MinecraftServer::setTimeOfDay = 0;
|
|||
bool MinecraftServer::m_bPrimaryPlayerSignedOut=false;
|
||||
bool MinecraftServer::s_bServerHalted=false;
|
||||
bool MinecraftServer::s_bSaveOnExitAnswered=false;
|
||||
bool MinecraftServer::s_bDeleteCurrentSaveOnNoSaveExit=false;
|
||||
int MinecraftServer::s_slowQueuePlayerIndex = 0;
|
||||
int MinecraftServer::s_slowQueueLastTime = 0;
|
||||
bool MinecraftServer::s_slowQueuePacketSent = false;
|
||||
|
|
@ -517,6 +523,7 @@ bool MinecraftServer::loadLevel(LevelStorageSource *storageSource, const wstring
|
|||
}
|
||||
app.SetGameHostOption( eGameHostOption_HasBeenInCreative, gameType == GameType::CREATIVE || levels[0]->getHasBeenInCreative() );
|
||||
app.SetGameHostOption( eGameHostOption_Structures, levels[0]->isGenerateMapFeatures() );
|
||||
WinsockNetLayer::UpdateAdvertiseGameHostSettings(app.GetGameHostOption(eGameHostOption_All));
|
||||
|
||||
if( s_bServerHalted || !g_NetworkManager.IsInSession() ) return false;
|
||||
|
||||
|
|
@ -881,6 +888,7 @@ bool MinecraftServer::IsSuspending()
|
|||
|
||||
void MinecraftServer::stopServer()
|
||||
{
|
||||
const bool shouldDeleteCurrentSaveOnNoSaveExit = (!m_saveOnExit && s_bDeleteCurrentSaveOnNoSaveExit);
|
||||
|
||||
// 4J-PB - need to halt the rendering of the data, since we're about to remove it
|
||||
#ifdef __PS3__
|
||||
|
|
@ -976,6 +984,40 @@ void MinecraftServer::stopServer()
|
|||
delete settings;
|
||||
settings = NULL;
|
||||
|
||||
if( shouldDeleteCurrentSaveOnNoSaveExit )
|
||||
{
|
||||
bool deleteRes = false;
|
||||
char uniqueFilename[32] = { 0 };
|
||||
|
||||
if (StorageManager.GetSaveUniqueFilename(uniqueFilename))
|
||||
{
|
||||
StorageManager.GetSavesInfo(ProfileManager.GetPrimaryPad(), NULL, NULL, "save");
|
||||
PSAVE_DETAILS pSaveDetails = StorageManager.ReturnSavesInfo();
|
||||
if (pSaveDetails != NULL)
|
||||
{
|
||||
const size_t uniqueLen = strlen(uniqueFilename);
|
||||
for (int i = 0; i < pSaveDetails->iSaveC; ++i)
|
||||
{
|
||||
const char *saveFilename = pSaveDetails->SaveInfoA[i].UTF8SaveFilename;
|
||||
const size_t saveLen = strlen(saveFilename);
|
||||
if (saveLen >= uniqueLen && strcmp(saveFilename + (saveLen - uniqueLen), uniqueFilename) == 0)
|
||||
{
|
||||
StorageManager.DeleteSaveData(&pSaveDetails->SaveInfoA[i], NULL, NULL);
|
||||
deleteRes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.DebugPrintf("No-save exit cleanup for new world: %s\n", deleteRes ? "success" : "failed");
|
||||
}
|
||||
s_bDeleteCurrentSaveOnNoSaveExit = false;
|
||||
|
||||
#if defined(WITH_SERVER_CODE) || defined(_WIN32)
|
||||
ServerThreadPool::Shutdown();
|
||||
#endif
|
||||
|
||||
g_NetworkManager.ServerStopped();
|
||||
}
|
||||
|
||||
|
|
@ -1516,24 +1558,89 @@ void MinecraftServer::tick()
|
|||
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
// if (i == 0 || settings->getBoolean(L"allow-nether", true)) // 4J removed - we always have nether
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
|
||||
// 4J Stu - We set the levels difficulty based on the minecraft options
|
||||
level->difficulty = app.GetGameHostOption(eGameHostOption_Difficulty); //pMinecraft->options->difficulty;
|
||||
|
||||
level->difficulty = app.GetGameHostOption(eGameHostOption_Difficulty);
|
||||
#if DEBUG_SERVER_DONT_SPAWN_MOBS
|
||||
level->setSpawnSettings(false, false);
|
||||
#else
|
||||
level->setSpawnSettings(level->difficulty > 0 && !Minecraft::GetInstance()->isTutorial(), animals);
|
||||
#endif
|
||||
|
||||
if (tickCount % 20 == 0)
|
||||
{
|
||||
players->broadcastAll( shared_ptr<SetTimePacket>( new SetTimePacket(level->getTime() ) ), level->dimension->id);
|
||||
}
|
||||
// #ifndef __PS3__
|
||||
}
|
||||
|
||||
#if defined(WITH_SERVER_CODE) || defined(_WIN32)
|
||||
if (!ServerThreadPool::IsInitialized())
|
||||
ServerThreadPool::Initialize();
|
||||
|
||||
struct DimensionTickData
|
||||
{
|
||||
ServerLevel *level;
|
||||
PlayerList *players;
|
||||
};
|
||||
|
||||
int activeLevels = 0;
|
||||
DimensionTickData dimData[3];
|
||||
for (unsigned int i = 0; i < levels.length && i < 3; i++)
|
||||
{
|
||||
dimData[i].level = levels[i];
|
||||
dimData[i].players = players;
|
||||
activeLevels++;
|
||||
}
|
||||
|
||||
if (activeLevels > 1 && ServerThreadPool::IsInitialized())
|
||||
{
|
||||
for (int i = 0; i < activeLevels; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Level *)dimData[i].level)->tick();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
ServerThreadPool::ParallelFor(0, activeLevels, [](int idx, void *param) {
|
||||
DimensionTickData *data = (DimensionTickData *)param;
|
||||
ServerLevel *level = data[idx].level;
|
||||
|
||||
try
|
||||
{
|
||||
while (level->updateLights())
|
||||
;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}, dimData);
|
||||
|
||||
for (int i = 0; i < activeLevels; i++)
|
||||
{
|
||||
ServerLevel *level = dimData[i].level;
|
||||
PlayerList *pPlayers = dimData[i].players;
|
||||
|
||||
try
|
||||
{
|
||||
if ((pPlayers->getPlayerCount(level) > 0) || (level->hasEntitiesToRemove()))
|
||||
level->tickEntities();
|
||||
|
||||
level->getTracker()->tick();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (unsigned int i = 0; i < levels.length; i++)
|
||||
{
|
||||
ServerLevel *level = levels[i];
|
||||
|
||||
static __int64 stc = 0;
|
||||
__int64 st0 = System::currentTimeMillis();
|
||||
PIXBeginNamedEvent(0,"Level tick %d",i);
|
||||
|
|
@ -1543,7 +1650,7 @@ void MinecraftServer::tick()
|
|||
PIXBeginNamedEvent(0,"Update lights %d",i);
|
||||
// 4J - used to be in a while loop, but we don't want the server locking up for a big chunk of time (could end up trying to process 1,000,000 lights...)
|
||||
// Instead call this once, which will try and process up to 2000 lights per tick
|
||||
// printf("lights: %d\n",level->getLightsToUpdate());
|
||||
//printf("lights: %d\n",level->getLightsToUpdate());
|
||||
while(level->updateLights() )
|
||||
;
|
||||
__int64 st2 = System::currentTimeMillis();
|
||||
|
|
@ -1556,7 +1663,7 @@ void MinecraftServer::tick()
|
|||
if( ( players->getPlayerCount(level) > 0) || ( level->hasEntitiesToRemove() ) )
|
||||
{
|
||||
#ifdef __PSVITA__
|
||||
// AP - the PlayerList->viewDistance initially starts out at 3 to make starting a level speedy
|
||||
// AP - the PlayerList->viewDistance initially starts out at 3 to make starting a level speedy
|
||||
// the problem with this is that spawned monsters are always generated on the edge of the known map
|
||||
// which means they wont process (unless they are surrounded by 2 visible chunks). This means
|
||||
// they wont checkDespawn so they are NEVER removed which results in monsters not spawning.
|
||||
|
|
@ -1575,16 +1682,15 @@ void MinecraftServer::tick()
|
|||
PIXEndNamedEvent();
|
||||
|
||||
__int64 st3 = System::currentTimeMillis();
|
||||
// printf(">>>>>>>>>>>>>>>>>>>>>> Tick %d %d %d : %d\n", st1 - st0, st2 - st1, st3 - st2, st0 - stc );
|
||||
stc = st0;
|
||||
// #endif// __PS3__
|
||||
}
|
||||
}
|
||||
Entity::tickExtraWandering(); // 4J added
|
||||
}
|
||||
}
|
||||
Entity::tickExtraWandering();
|
||||
|
||||
#ifdef WITH_SERVER_CODE
|
||||
#if defined(WITH_SERVER_CODE) || defined(_WIN32)
|
||||
g_NetworkManager.DoWork();
|
||||
WinsockNetLayer::FlushPendingData();
|
||||
WinsockNetLayer::FlushSendBuffers();
|
||||
#endif
|
||||
|
||||
PIXBeginNamedEvent(0,"Connection tick");
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ public:
|
|||
static MinecraftServer *getInstance() { return server; } // 4J added
|
||||
static bool serverHalted() { return s_bServerHalted; }
|
||||
static bool saveOnExitAnswered() { return s_bSaveOnExitAnswered; }
|
||||
static void resetFlags() { s_bServerHalted = false; s_bSaveOnExitAnswered = false; }
|
||||
static void resetFlags() { s_bServerHalted = false; s_bSaveOnExitAnswered = false; s_bDeleteCurrentSaveOnNoSaveExit = false; }
|
||||
static void SetDeleteOnNoSaveForCurrentSession(bool bDelete) { s_bDeleteCurrentSaveOnNoSaveExit = bDelete; }
|
||||
|
||||
bool flagEntitiesToBeRemoved(unsigned int *flags); // 4J added
|
||||
private:
|
||||
|
|
@ -192,6 +193,7 @@ private:
|
|||
static bool m_bPrimaryPlayerSignedOut; // 4J-PB added to tell the stopserver not to save the game - another player may have signed in in their place, so ProfileManager.IsSignedIn isn't enough
|
||||
static bool s_bServerHalted; // 4J Stu Added so that we can halt the server even before it's been created properly
|
||||
static bool s_bSaveOnExitAnswered; // 4J Stu Added so that we only ask this question once when we exit
|
||||
static bool s_bDeleteCurrentSaveOnNoSaveExit;
|
||||
|
||||
// 4J - added so that we can have a separate thread for post processing chunks on level creation
|
||||
static int runPostUpdate(void* lpParam);
|
||||
|
|
|
|||
|
|
@ -603,18 +603,19 @@ bool MultiPlayerLevel::doSetTileAndData(int x, int y, int z, int tile, int data)
|
|||
|
||||
void MultiPlayerLevel::disconnect(bool sendDisconnect /*= true*/)
|
||||
{
|
||||
vector<ClientConnection *> connectionsTemp = connections;
|
||||
if( sendDisconnect )
|
||||
{
|
||||
for(AUTO_VAR(it, connections.begin()); it < connections.end(); ++it )
|
||||
for(AUTO_VAR(it, connectionsTemp.begin()); it < connectionsTemp.end(); ++it )
|
||||
{
|
||||
(*it)->sendAndDisconnect( shared_ptr<DisconnectPacket>( new DisconnectPacket(DisconnectPacket::eDisconnect_Quitting) ) );
|
||||
if( *it ) (*it)->sendAndDisconnect( shared_ptr<DisconnectPacket>( new DisconnectPacket(DisconnectPacket::eDisconnect_Quitting) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(AUTO_VAR(it, connections.begin()); it < connections.end(); ++it )
|
||||
for(AUTO_VAR(it, connectionsTemp.begin()); it < connectionsTemp.end(); ++it )
|
||||
{
|
||||
(*it)->close();
|
||||
if( *it ) (*it)->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,11 @@ void MultiplayerLocalPlayer::reallyDrop(shared_ptr<ItemEntity> itemEntity)
|
|||
|
||||
void MultiplayerLocalPlayer::chat(const wstring& message)
|
||||
{
|
||||
if (app.GetGameHostOption(eGameHostOption_ChatDisabled) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
connection->send( shared_ptr<ChatPacket>( new ChatPacket(message) ) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -407,6 +407,12 @@ public:
|
|||
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
|
||||
D3D11_RASTERIZER_DESC rasterizerDesc;
|
||||
float blendFactor[4];
|
||||
float m_cachedLocalMatrix[16];
|
||||
float m_cachedCompressedTranslation[4];
|
||||
float m_cachedTintColor[4];
|
||||
bool fogDirty;
|
||||
bool texGenDirty;
|
||||
int m_cachedSamplerKey;
|
||||
};
|
||||
|
||||
static DWORD tlsIdx;
|
||||
|
|
|
|||
|
|
@ -292,17 +292,25 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con
|
|||
command.add_matrix.m_matrix[12], command.add_matrix.m_matrix[13],
|
||||
command.add_matrix.m_matrix[14], command.add_matrix.m_matrix[15]
|
||||
};
|
||||
D3D11_MAPPED_SUBRESOURCE mappedAux0 = {};
|
||||
c.m_pDeviceContext->Map(c.m_compressedTranslationBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedAux0);
|
||||
memcpy(mappedAux0.pData, row, sizeof(row));
|
||||
c.m_pDeviceContext->Unmap(c.m_compressedTranslationBuffer, 0);
|
||||
if (memcmp(row, c.m_cachedCompressedTranslation, sizeof(row)) != 0)
|
||||
{
|
||||
memcpy(c.m_cachedCompressedTranslation, row, sizeof(row));
|
||||
D3D11_MAPPED_SUBRESOURCE mappedAux0 = {};
|
||||
c.m_pDeviceContext->Map(c.m_compressedTranslationBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedAux0);
|
||||
memcpy(mappedAux0.pData, row, sizeof(row));
|
||||
c.m_pDeviceContext->Unmap(c.m_compressedTranslationBuffer, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mappedMatrix1 = {};
|
||||
c.m_pDeviceContext->Map(c.m_localTransformMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix1);
|
||||
memcpy(mappedMatrix1.pData, command.add_matrix.m_matrix, sizeof(command.add_matrix.m_matrix));
|
||||
c.m_pDeviceContext->Unmap(c.m_localTransformMatrix, 0);
|
||||
if (memcmp(command.add_matrix.m_matrix, c.m_cachedLocalMatrix, sizeof(c.m_cachedLocalMatrix)) != 0)
|
||||
{
|
||||
memcpy(c.m_cachedLocalMatrix, command.add_matrix.m_matrix, sizeof(c.m_cachedLocalMatrix));
|
||||
D3D11_MAPPED_SUBRESOURCE mappedMatrix1 = {};
|
||||
c.m_pDeviceContext->Map(c.m_localTransformMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix1);
|
||||
memcpy(mappedMatrix1.pData, command.add_matrix.m_matrix, sizeof(command.add_matrix.m_matrix));
|
||||
c.m_pDeviceContext->Unmap(c.m_localTransformMatrix, 0);
|
||||
}
|
||||
matrixOverride = true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -311,7 +319,8 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con
|
|||
{
|
||||
if (isActive)
|
||||
{
|
||||
InternalRenderManager.UpdateLightingState();
|
||||
if (c.lightingDirty && c.lightingEnabled)
|
||||
InternalRenderManager.UpdateLightingState();
|
||||
|
||||
if (drawVertexType == C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1)
|
||||
{
|
||||
|
|
@ -369,10 +378,14 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con
|
|||
}
|
||||
case COMMAND_SET_COLOR:
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mappedColour = {};
|
||||
c.m_pDeviceContext->Map(c.m_tintColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedColour);
|
||||
memcpy(mappedColour.pData, command.set_color.m_color, sizeof(command.set_color.m_color));
|
||||
c.m_pDeviceContext->Unmap(c.m_tintColorBuffer, 0);
|
||||
if (memcmp(command.set_color.m_color, c.m_cachedTintColor, sizeof(c.m_cachedTintColor)) != 0)
|
||||
{
|
||||
memcpy(c.m_cachedTintColor, command.set_color.m_color, sizeof(c.m_cachedTintColor));
|
||||
D3D11_MAPPED_SUBRESOURCE mappedColour = {};
|
||||
c.m_pDeviceContext->Map(c.m_tintColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedColour);
|
||||
memcpy(mappedColour.pData, command.set_color.m_color, sizeof(command.set_color.m_color));
|
||||
c.m_pDeviceContext->Unmap(c.m_tintColorBuffer, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COMMAND_SET_DEPTH_FUNC:
|
||||
|
|
@ -486,6 +499,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con
|
|||
c.m_pDeviceContext->Map(c.m_localTransformMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedIdentity);
|
||||
memcpy(mappedIdentity.pData, &identity, sizeof(identity));
|
||||
c.m_pDeviceContext->Unmap(c.m_localTransformMatrix, 0);
|
||||
memcpy(c.m_cachedLocalMatrix, &identity, sizeof(identity));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ SOFTWARE.
|
|||
#include "Renderer.h"
|
||||
#include "CompiledShaders.h"
|
||||
|
||||
#ifndef DXGI_PRESENT_ALLOW_TEARING
|
||||
#define DXGI_PRESENT_ALLOW_TEARING 0x00000200
|
||||
#endif
|
||||
|
||||
#ifndef DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING
|
||||
#define DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING 2048
|
||||
#endif
|
||||
|
||||
Renderer InternalRenderManager;
|
||||
|
||||
DWORD Renderer::tlsIdx = TlsAlloc();
|
||||
|
|
@ -132,6 +140,19 @@ Renderer::Context::Context(ID3D11Device* device, ID3D11DeviceContext* deviceCont
|
|||
stackPos[i] = 0;
|
||||
}
|
||||
|
||||
memcpy(m_cachedLocalMatrix, &identity, sizeof(m_cachedLocalMatrix));
|
||||
m_cachedCompressedTranslation[0] = 0.0f;
|
||||
m_cachedCompressedTranslation[1] = 0.0f;
|
||||
m_cachedCompressedTranslation[2] = 0.0f;
|
||||
m_cachedCompressedTranslation[3] = 0.0f;
|
||||
m_cachedTintColor[0] = 1.0f;
|
||||
m_cachedTintColor[1] = 1.0f;
|
||||
m_cachedTintColor[2] = 1.0f;
|
||||
m_cachedTintColor[3] = 1.0f;
|
||||
fogDirty = true;
|
||||
texGenDirty = true;
|
||||
m_cachedSamplerKey = -1;
|
||||
|
||||
blendDesc.AlphaToCoverageEnable = false;
|
||||
blendDesc.IndependentBlendEnable = false;
|
||||
blendDesc.RenderTarget[0].BlendEnable = false;
|
||||
|
|
@ -667,7 +688,16 @@ void Renderer::Present()
|
|||
m_bShouldScreenGrabNextFrame = false;
|
||||
}
|
||||
|
||||
m_pSwapChain->Present(0, 0);
|
||||
UINT presentFlags = 0;
|
||||
|
||||
if (m_pSwapChain)
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc = {};
|
||||
if (SUCCEEDED(m_pSwapChain->GetDesc(&swapDesc)) && (swapDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) != 0)
|
||||
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
m_pSwapChain->Present(0, presentFlags);
|
||||
++presentCount;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ void Renderer::StateSetColour(float r, float g, float b, float a)
|
|||
|
||||
ID3D11DeviceContext *d3d11 = c.m_pDeviceContext;
|
||||
const float colour[4] = {r, g, b, a};
|
||||
memcpy(c.m_cachedTintColor, colour, sizeof(c.m_cachedTintColor));
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapped = {};
|
||||
d3d11->Map(c.m_tintColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
|
||||
|
|
|
|||
|
|
@ -9545,7 +9545,7 @@ void* MicroProfileTraceThread(void* unused)
|
|||
MicroProfileWin32ContextSwitchShared* pShared = 0;
|
||||
char Filename[512];
|
||||
time_t t = time(NULL);
|
||||
_snprintf_s(Filename, sizeof(Filename), "%s_%d", MICROPROFILE_FILEMAPPING, (int)t);
|
||||
snprintf(Filename, sizeof(Filename), "%s_%d", MICROPROFILE_FILEMAPPING, (int)t);
|
||||
|
||||
HANDLE hMemory = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(MicroProfileWin32ContextSwitchShared), Filename);
|
||||
if(hMemory != NULL)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ C4JStorage::EDLCStatus CDLC::GetInstalledDLC(int iPad, int (*Func)(LPVOID, int,
|
|||
{
|
||||
XCONTENT_DATA data;
|
||||
snprintf(data.szFileName, sizeof(data.szFileName), "%s/%s", dlcDir, entry->d_name);
|
||||
swprintf(data.szDisplayName, 256, L"%s", entry->d_name);
|
||||
swprintf(data.szDisplayName, XCONTENT_MAX_DISPLAYNAME_LENGTH, L"%hs", entry->d_name);
|
||||
data.DeviceID = 0;
|
||||
data.dwContentType = 0;
|
||||
AddInstalled(&data);
|
||||
|
|
@ -157,8 +157,7 @@ C4JStorage::EDLCStatus CDLC::GetInstalledDLC(int iPad, int (*Func)(LPVOID, int,
|
|||
sprintf(data.szFileName, "Windows64Media/DLC/%s", hFind.cFileName);
|
||||
}
|
||||
|
||||
swprintf(data.szDisplayName, 256, L"%s", hFind.cFileName);
|
||||
int displayNameLen = wcslen(data.szDisplayName);
|
||||
swprintf(data.szDisplayName, XCONTENT_MAX_DISPLAYNAME_LENGTH, L"%hs", hFind.cFileName);
|
||||
|
||||
data.DeviceID = 0;
|
||||
data.dwContentType = 0;
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ void CSaveGame::ResetSaveData()
|
|||
free(m_pSaveData);
|
||||
m_pSaveData = nullptr;
|
||||
m_uiSaveSize = 0;
|
||||
m_szSaveUniqueName[0] = '\0';
|
||||
}
|
||||
|
||||
C4JStorage::ESaveGameState CSaveGame::GetSavesInfo(int iPad, int (*Func)(LPVOID lpParam, SAVE_DETAILS *pSaveDetails, const bool), LPVOID lpParam,
|
||||
|
|
|
|||
|
|
@ -46,10 +46,12 @@ public:
|
|||
bool GetSaveUniqueFilename(char *pszName);
|
||||
void SetSaveTitle(LPCWSTR pwchDefaultSaveName);
|
||||
PVOID AllocateSaveData(unsigned int uiBytes);
|
||||
void SetSaveDataSize(unsigned int uiBytes);
|
||||
void SetSaveImages(PBYTE pbThumbnail, DWORD dwThumbnailBytes, PBYTE pbImage, DWORD dwImageBytes, PBYTE pbTextData, DWORD dwTextDataBytes);
|
||||
C4JStorage::ESaveGameState SaveSaveData(int (*Func)(LPVOID, const bool), LPVOID lpParam);
|
||||
void CopySaveDataToNewSave(PBYTE pbThumbnail, DWORD cbThumbnail, WCHAR *wchNewName, int (*Func)(LPVOID lpParam, bool), LPVOID lpParam);
|
||||
C4JStorage::ESaveGameState DeleteSaveData(PSAVE_INFO pSaveInfo, int (*Func)(LPVOID lpParam, const bool), LPVOID lpParam);
|
||||
bool DeleteCurrentSaveData();
|
||||
C4JStorage::ESaveGameState RenameSaveData(int iRenameIndex, uint16_t *pui16NewName, int (*Func)(LPVOID lpParam, const bool), LPVOID lpParam);
|
||||
C4JStorage::ESaveGameState DoesSaveExist(bool *pbExists);
|
||||
void SetSaveUniqueFilename(char *szFilename);
|
||||
|
|
|
|||
|
|
@ -500,7 +500,24 @@ void PlayerChunkMap::getChunkAndRemovePlayer(int x, int z, shared_ptr<ServerPlay
|
|||
void PlayerChunkMap::tickAddRequests(shared_ptr<ServerPlayer> player)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
const int maxPerTick = 10;
|
||||
int maxPerTick = 10;
|
||||
#if defined(_DEDICATED_SERVER)
|
||||
int activePlayers = (int)players.size();
|
||||
if (activePlayers < 1)
|
||||
{
|
||||
activePlayers = 1;
|
||||
}
|
||||
|
||||
maxPerTick = 48 / activePlayers;
|
||||
if (maxPerTick < 1)
|
||||
{
|
||||
maxPerTick = 1;
|
||||
}
|
||||
if (maxPerTick > 10)
|
||||
{
|
||||
maxPerTick = 10;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
const int maxPerTick = 1;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,11 +29,24 @@ bool g_voiceChatEnabled = true;
|
|||
#include "ServerConnection.h"
|
||||
#include "../Minecraft.World/GenericStats.h"
|
||||
#include "../Minecraft.World/JavaMath.h"
|
||||
#include "../Minecraft.World/StringHelpers.h"
|
||||
|
||||
// 4J Added
|
||||
#include "../Minecraft.World/net.minecraft.world.item.crafting.h"
|
||||
#include "Options.h"
|
||||
|
||||
#ifdef WITH_SERVER_CODE
|
||||
#include "../Minecraft.Server/Commands/ServerCommands.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
bool IsTextChatDisabledForSession()
|
||||
{
|
||||
return app.GetGameHostOption(eGameHostOption_ChatDisabled) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
Random PlayerConnection::random;
|
||||
|
||||
PlayerConnection::PlayerConnection(MinecraftServer *server, Connection *connection, shared_ptr<ServerPlayer> player)
|
||||
|
|
@ -156,7 +169,16 @@ void PlayerConnection::handlePlayerInput(shared_ptr<PlayerInputPacket> packet)
|
|||
|
||||
void PlayerConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
|
||||
{
|
||||
if (done || player == NULL || player->gameMode == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerLevel *level = server->getLevel(player->dimension);
|
||||
if (level == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
didTick = true;
|
||||
if(synched) m_bHasClientTickedOnce = true;
|
||||
|
|
@ -591,7 +613,11 @@ void PlayerConnection::handleUseItem(shared_ptr<UseItemPacket> packet)
|
|||
void PlayerConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason, void *reasonObjects)
|
||||
{
|
||||
EnterCriticalSection(&done_cs);
|
||||
if( done ) return;
|
||||
if( done )
|
||||
{
|
||||
LeaveCriticalSection(&done_cs);
|
||||
return;
|
||||
}
|
||||
// logger.info(player.name + " lost connection: " + reason);
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//server->players->broadcastAll( shared_ptr<ChatPacket>( new ChatPacket(L"�e" + player->name + L" left the game.") ) );
|
||||
|
|
@ -661,45 +687,73 @@ void PlayerConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac
|
|||
|
||||
void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
||||
{
|
||||
// 4J - TODO
|
||||
#if 0
|
||||
wstring message = packet->message;
|
||||
if (message.length() > SharedConstants::maxChatLength)
|
||||
if (IsTextChatDisabledForSession())
|
||||
{
|
||||
disconnect(L"Chat message too long");
|
||||
send(shared_ptr<ChatPacket>(new ChatPacket(L"Chat is disabled on this server.")));
|
||||
return;
|
||||
}
|
||||
message = message.trim();
|
||||
for (int i = 0; i < message.length(); i++)
|
||||
|
||||
wstring rawMessage;
|
||||
if (!packet->m_stringArgs.empty())
|
||||
{
|
||||
if (SharedConstants.acceptableLetters.indexOf(message.charAt(i)) < 0 && (int) message.charAt(i) < 32)
|
||||
rawMessage = packet->m_stringArgs[0];
|
||||
}
|
||||
|
||||
// ported from java 1.3.1 NetServerHandler: reject overlong chat payloads.
|
||||
if (rawMessage.length() > SharedConstants::maxChatLength)
|
||||
{
|
||||
disconnect(DisconnectPacket::eDisconnect_Kicked);
|
||||
return;
|
||||
}
|
||||
|
||||
wstring message = trimString(rawMessage);
|
||||
|
||||
// ported from java 1.3.1 ChatAllowedCharacters.isAllowedCharacter(c)
|
||||
for (unsigned int i = 0; i < message.length(); i++)
|
||||
{
|
||||
const wchar_t ch = message[i];
|
||||
if (ch == 0x00A7 || (SharedConstants::acceptableLetters.find(ch) == wstring::npos && ch <= L' '))
|
||||
{
|
||||
disconnect(L"Illegal characters in chat");
|
||||
disconnect(DisconnectPacket::eDisconnect_Kicked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (message.startsWith("/"))
|
||||
if (!message.empty() && message[0] == L'/')
|
||||
{
|
||||
handleCommand(message);
|
||||
} else {
|
||||
message = "<" + player.name + "> " + message;
|
||||
logger.info(message);
|
||||
server.players.broadcastAll(new ChatPacket(message));
|
||||
}
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||
else
|
||||
{
|
||||
disconnect("disconnect.spam");
|
||||
wstring formatted = L"<" + player->name + L"> " + message;
|
||||
app.DebugPrintf("%ls", formatted.c_str());
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
|
||||
}
|
||||
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10 && !server->getPlayers()->isOp(player) && !server->getPlayers()->isOp(player->name))
|
||||
{
|
||||
disconnect(DisconnectPacket::eDisconnect_Kicked);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlayerConnection::handleCommand(const wstring& message)
|
||||
{
|
||||
// 4J - TODO
|
||||
#if 0
|
||||
server.getCommandDispatcher().performCommand(player, message);
|
||||
if (IsTextChatDisabledForSession())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const bool canUseCommands = server->getPlayers()->isOp(player) || server->getPlayers()->isOp(player->name);
|
||||
if (!canUseCommands && message != L"/seed")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
app.DebugPrintf("%ls issued server command: %ls", player->name.c_str(), message.c_str());
|
||||
|
||||
#ifdef WITH_SERVER_CODE
|
||||
HandleServerCommand(message, this, server);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -764,14 +818,12 @@ int PlayerConnection::countDelayedPackets()
|
|||
|
||||
void PlayerConnection::info(const wstring& string)
|
||||
{
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//send( shared_ptr<ChatPacket>( new ChatPacket(L"�7" + string) ) );
|
||||
send(shared_ptr<ChatPacket>(new ChatPacket(string)));
|
||||
}
|
||||
|
||||
void PlayerConnection::warn(const wstring& string)
|
||||
{
|
||||
// 4J-PB - removed, since it needs to be localised in the language the client is in
|
||||
//send( shared_ptr<ChatPacket>( new ChatPacket(L"�9" + string) ) );
|
||||
send(shared_ptr<ChatPacket>(new ChatPacket(string)));
|
||||
}
|
||||
|
||||
wstring PlayerConnection::getConsoleName()
|
||||
|
|
|
|||
|
|
@ -133,11 +133,14 @@ void PlayerList::placeNewPlayer(Connection *connection, shared_ptr<ServerPlayer>
|
|||
|
||||
DWORD playerIndex = 0;
|
||||
{
|
||||
bool usedIndexes[32];
|
||||
ZeroMemory( &usedIndexes, 32 * sizeof(bool) );
|
||||
vector<char> usedIndexes(maxPlayers, 0);
|
||||
for(AUTO_VAR(it, players.begin()); it < players.end(); ++it)
|
||||
{
|
||||
usedIndexes[ (int)(*it)->getPlayerIndex() ] = true;
|
||||
int existingIndex = (int)(*it)->getPlayerIndex();
|
||||
if (existingIndex >= 0 && existingIndex < (int)usedIndexes.size())
|
||||
{
|
||||
usedIndexes[existingIndex] = 1;
|
||||
}
|
||||
}
|
||||
for(unsigned int i = 0; i < (unsigned int)maxPlayers; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -848,6 +848,7 @@ bool ServerChunkCache::save(bool force, ProgressListener *progressListener)
|
|||
LeaveCriticalSection(&m_csLoadCreate);
|
||||
return true;
|
||||
}
|
||||
storage->WaitForAll();
|
||||
storage->flush();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#include "../Minecraft.World/Socket.h"
|
||||
#include "../Minecraft.World/net.minecraft.world.level.h"
|
||||
#include "MultiPlayerLevel.h"
|
||||
#ifdef WITH_SERVER_CODE
|
||||
#include "../Minecraft.Server/Core/ServerThreadPool.h"
|
||||
#endif
|
||||
|
||||
ServerConnection::ServerConnection(MinecraftServer *server)
|
||||
{
|
||||
|
|
@ -98,16 +101,12 @@ void ServerConnection::tick()
|
|||
{
|
||||
serverPlayer->doChunkSendingTick(false);
|
||||
}
|
||||
// try { // 4J - removed try/catch
|
||||
player->tick();
|
||||
// } catch (Exception e) {
|
||||
// logger.log(Level.WARNING, "Failed to handle packet: " + e, e);
|
||||
// player.disconnect("Internal server error");
|
||||
// }
|
||||
if (player->done)
|
||||
{
|
||||
players.erase(players.begin()+i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
player->connection->flush();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,10 +306,38 @@ void ServerPlayer::doTickA()
|
|||
// 4J - split off the chunk sending bit of the tick here from ::doTick so we can do this exactly once per player per server tick
|
||||
void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
for (int _w64cs = 0; _w64cs < 4; _w64cs++)
|
||||
int chunkSendPasses = 1;
|
||||
|
||||
#if defined(_DEDICATED_SERVER)
|
||||
int activePlayers = 1;
|
||||
if (server != NULL && server->getPlayers() != NULL)
|
||||
{
|
||||
ServerLevel *serverLevel = server->getLevel(dimension);
|
||||
if (serverLevel != NULL)
|
||||
{
|
||||
activePlayers = server->getPlayers()->getPlayerCount(serverLevel);
|
||||
}
|
||||
}
|
||||
if (activePlayers < 1)
|
||||
{
|
||||
activePlayers = 1;
|
||||
}
|
||||
|
||||
chunkSendPasses = 32 / activePlayers;
|
||||
if (chunkSendPasses < 1)
|
||||
{
|
||||
chunkSendPasses = 1;
|
||||
}
|
||||
if (chunkSendPasses > 4)
|
||||
{
|
||||
chunkSendPasses = 4;
|
||||
}
|
||||
#elif defined(_WINDOWS64)
|
||||
chunkSendPasses = 4;
|
||||
#endif
|
||||
|
||||
for (int _w64cs = 0; _w64cs < chunkSendPasses; _w64cs++)
|
||||
{
|
||||
// printf("[%d] %s: sendChunks: %d, empty: %d\n",tickCount, connection->getNetworkPlayer()->GetUID().getOnlineID(),sendChunks,chunksToSend.empty());
|
||||
if (!chunksToSend.empty())
|
||||
{
|
||||
|
|
@ -469,9 +497,7 @@ void ServerPlayer::doChunkSendingTick(bool dontDelayChunks)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef _WINDOWS64
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerPlayer::doTickB(bool ignorePortal)
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ public:
|
|||
void GetDefaultSaveThumbnail(PBYTE *ppbSaveThumbnail,DWORD *pdwSaveThumbnailBytes); // Get the default save thumbnail (as set by SetDefaultImages)
|
||||
C4JStorage::ESaveGameState SaveSaveData(int( *Func)(LPVOID ,const bool),LPVOID lpParam);
|
||||
void CopySaveDataToNewSave(PBYTE pbThumbnail,DWORD cbThumbnail,WCHAR *wchNewName,int ( *Func)(LPVOID lpParam, bool), LPVOID lpParam);
|
||||
bool DeleteCurrentSaveData();
|
||||
void SetSaveDeviceSelected(unsigned int uiPad,bool bSelected);
|
||||
bool GetSaveDeviceSelected(unsigned int iPad);
|
||||
C4JStorage::ESaveGameState DoesSaveExist(bool *pbExists);
|
||||
|
|
|
|||
84
Minecraft.Client/Windows64/GammaPostProcessPS.h
Normal file
84
Minecraft.Client/Windows64/GammaPostProcessPS.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
static unsigned char g_gammaPostProcessPS[] =
|
||||
{
|
||||
0x44, 0x58, 0x42, 0x43, 0x0B, 0x31, 0x1E, 0xA8, 0x65, 0xFA, 0xD7, 0xE5,
|
||||
0xEC, 0xF8, 0xBC, 0xF2, 0xF3, 0x82, 0x8E, 0xC5, 0x01, 0x00, 0x00, 0x00,
|
||||
0xAC, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||
0x74, 0x01, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x38, 0x01, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00,
|
||||
0x10, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x89, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x6E, 0x65, 0x53, 0x61, 0x6D,
|
||||
0x70, 0x6C, 0x65, 0x72, 0x00, 0x73, 0x63, 0x65, 0x6E, 0x65, 0x54, 0x65,
|
||||
0x78, 0x00, 0x47, 0x61, 0x6D, 0x6D, 0x61, 0x43, 0x42, 0x00, 0xAB, 0xAB,
|
||||
0x92, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x67, 0x61, 0x6D, 0x6D, 0x61, 0x00, 0xAB, 0xAB, 0x00, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x61, 0x64, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72,
|
||||
0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C,
|
||||
0x53, 0x4C, 0x20, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F,
|
||||
0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00,
|
||||
0x49, 0x53, 0x47, 0x4E, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x03, 0x03, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6F, 0x6E, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44,
|
||||
0x00, 0xAB, 0xAB, 0xAB, 0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52,
|
||||
0x28, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00,
|
||||
0x59, 0x00, 0x00, 0x04, 0x46, 0x8E, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, 0x00, 0x70, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03,
|
||||
0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03,
|
||||
0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02,
|
||||
0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x0A, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x45, 0x00, 0x00, 0x09, 0xF2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x46, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x34, 0x00, 0x00, 0x0A, 0xE2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 0x09, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x82, 0x20, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x2F, 0x00, 0x00, 0x05, 0xE2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x56, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07,
|
||||
0x72, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x07, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x46, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01,
|
||||
0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
62
Minecraft.Client/Windows64/GammaPostProcessVS.h
Normal file
62
Minecraft.Client/Windows64/GammaPostProcessVS.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
static unsigned char g_gammaPostProcessVS[] =
|
||||
{
|
||||
0x44, 0x58, 0x42, 0x43, 0x49, 0xE1, 0x2B, 0x34, 0xAF, 0x05, 0x7D, 0xD8,
|
||||
0xBF, 0x25, 0xB1, 0x3F, 0xEA, 0x1E, 0x2C, 0x90, 0x01, 0x00, 0x00, 0x00,
|
||||
0xA8, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x0C, 0x01, 0x00, 0x00,
|
||||
0x2C, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x44, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFE, 0xFF, 0x00, 0x01, 0x00, 0x00,
|
||||
0x1C, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
|
||||
0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53,
|
||||
0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C,
|
||||
0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E,
|
||||
0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
|
||||
0x53, 0x56, 0x5F, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00,
|
||||
0x4F, 0x53, 0x47, 0x4E, 0x50, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x03, 0x0C, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6F, 0x6E, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44,
|
||||
0x00, 0xAB, 0xAB, 0xAB, 0x53, 0x48, 0x44, 0x52, 0x18, 0x01, 0x00, 0x00,
|
||||
0x40, 0x00, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x04,
|
||||
0x12, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
|
||||
0x29, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0A, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x12, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07,
|
||||
0x42, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x10, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x56, 0x00, 0x00, 0x05, 0x32, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x86, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0F,
|
||||
0x32, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
|
||||
0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05,
|
||||
0x32, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x08, 0xC2, 0x20, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
|
@ -6,9 +6,64 @@
|
|||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#if defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static KBMConfig s_config;
|
||||
static bool s_loaded = false;
|
||||
static void WriteDefaultINI(const char* path);
|
||||
|
||||
static bool BuildAppDataINIPath(char* outPath, size_t outSize)
|
||||
{
|
||||
if (!outPath || outSize == 0) return false;
|
||||
|
||||
char dirPath[MAX_PATH];
|
||||
int written = 0;
|
||||
#if defined(__linux__)
|
||||
const char* baseDir = getenv("XDG_DATA_HOME");
|
||||
if (baseDir != NULL && baseDir[0] != 0)
|
||||
{
|
||||
written = snprintf(dirPath, MAX_PATH, "%s/minecraft", baseDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
baseDir = getenv("HOME");
|
||||
if (baseDir == NULL || baseDir[0] == 0) return false;
|
||||
written = snprintf(dirPath, MAX_PATH, "%s/.minecraft", baseDir);
|
||||
}
|
||||
#else
|
||||
const char* baseDir = getenv("APPDATA");
|
||||
if (baseDir == NULL || baseDir[0] == 0) return false;
|
||||
written = _snprintf_s(dirPath, MAX_PATH, _TRUNCATE, "%s\\Minecraft", baseDir);
|
||||
#endif
|
||||
if (written <= 0 || written >= MAX_PATH) return false;
|
||||
|
||||
CreateDirectoryA(dirPath, NULL);
|
||||
|
||||
#if defined(__linux__)
|
||||
written = snprintf(outPath, outSize, "%s/kbm_config.ini", dirPath);
|
||||
#else
|
||||
written = _snprintf_s(outPath, outSize, _TRUNCATE, "%s\\kbm_config.ini", dirPath);
|
||||
#endif
|
||||
if (written <= 0 || (size_t)written >= outSize) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static FILE* OpenINIWithCreate(const char* path)
|
||||
{
|
||||
if (!path || !path[0]) return NULL;
|
||||
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f)
|
||||
{
|
||||
WriteDefaultINI(path);
|
||||
f = fopen(path, "r");
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static int ParseVK(const char* val)
|
||||
{
|
||||
|
|
@ -70,6 +125,7 @@ static void WriteDefaultINI(const char* path)
|
|||
fprintf(f, "sprint=LCONTROL\n");
|
||||
fprintf(f, "inventory=E\n");
|
||||
fprintf(f, "drop=Q\n");
|
||||
fprintf(f, "chat=T\n");
|
||||
fprintf(f, "crafting=TAB\n");
|
||||
fprintf(f, "confirm=RETURN\n");
|
||||
fprintf(f, "pause=ESCAPE\n");
|
||||
|
|
@ -100,6 +156,7 @@ void KBMConfig::Load()
|
|||
keySprint = VK_LCONTROL;
|
||||
keyInventory = 'E';
|
||||
keyDrop = 'Q';
|
||||
keyChat = 'T';
|
||||
keyCrafting = VK_TAB;
|
||||
keyConfirm = VK_RETURN;
|
||||
keyPause = VK_ESCAPE;
|
||||
|
|
@ -110,21 +167,40 @@ void KBMConfig::Load()
|
|||
s_loaded = true;
|
||||
|
||||
char exePath[MAX_PATH];
|
||||
#if defined(__linux__)
|
||||
if (getcwd(exePath, sizeof(exePath)) == NULL) return;
|
||||
size_t exeLen = strlen(exePath);
|
||||
if (exeLen + 1 >= MAX_PATH) return;
|
||||
if (exeLen > 0 && exePath[exeLen - 1] != '/')
|
||||
{
|
||||
exePath[exeLen] = '/';
|
||||
exePath[exeLen + 1] = 0;
|
||||
}
|
||||
#else
|
||||
if (!GetModuleFileNameA(NULL, exePath, MAX_PATH)) return;
|
||||
|
||||
char* slash = strrchr(exePath, '\\');
|
||||
if (slash) *(slash + 1) = 0;
|
||||
#endif
|
||||
|
||||
char iniPath[MAX_PATH];
|
||||
_snprintf_s(iniPath, MAX_PATH, _TRUNCATE, "%skbm_config.ini", exePath);
|
||||
#if defined(__linux__)
|
||||
int written = snprintf(iniPath, MAX_PATH, "%skbm_config.ini", exePath);
|
||||
#else
|
||||
int written = _snprintf_s(iniPath, MAX_PATH, _TRUNCATE, "%skbm_config.ini", exePath);
|
||||
#endif
|
||||
if (written <= 0 || written >= MAX_PATH) return;
|
||||
|
||||
FILE* f = fopen(iniPath, "r");
|
||||
FILE* f = OpenINIWithCreate(iniPath);
|
||||
if (!f)
|
||||
{
|
||||
WriteDefaultINI(iniPath);
|
||||
return;
|
||||
char appDataINIPath[MAX_PATH];
|
||||
if (BuildAppDataINIPath(appDataINIPath, MAX_PATH))
|
||||
f = OpenINIWithCreate(appDataINIPath);
|
||||
}
|
||||
|
||||
if (!f) return;
|
||||
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
|
|
@ -160,6 +236,7 @@ void KBMConfig::Load()
|
|||
else if (_stricmp(key, "sprint") == 0) { int v = ParseVK(val); if (v) keySprint = v; }
|
||||
else if (_stricmp(key, "inventory") == 0) { int v = ParseVK(val); if (v) keyInventory = v; }
|
||||
else if (_stricmp(key, "drop") == 0) { int v = ParseVK(val); if (v) keyDrop = v; }
|
||||
else if (_stricmp(key, "chat") == 0) { int v = ParseVK(val); if (v) keyChat = v; }
|
||||
else if (_stricmp(key, "crafting") == 0) { int v = ParseVK(val); if (v) keyCrafting = v; }
|
||||
else if (_stricmp(key, "confirm") == 0) { int v = ParseVK(val); if (v) keyConfirm = v; }
|
||||
else if (_stricmp(key, "pause") == 0) { int v = ParseVK(val); if (v) keyPause = v; }
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ struct KBMConfig
|
|||
int keySprint;
|
||||
int keyInventory;
|
||||
int keyDrop;
|
||||
int keyChat;
|
||||
int keyCrafting;
|
||||
int keyConfirm;
|
||||
int keyPause;
|
||||
|
|
|
|||
|
|
@ -2,4 +2,591 @@
|
|||
|
||||
#include "WindowsLeaderboardManager.h"
|
||||
|
||||
LeaderboardManager *LeaderboardManager::m_instance = new WindowsLeaderboardManager(); //Singleton instance of the LeaderboardManager
|
||||
#include "../../StatsCounter.h"
|
||||
|
||||
#include "../../../Minecraft.World/Stats.h"
|
||||
#include "../../../Minecraft.World/net.minecraft.world.item.h"
|
||||
#include "../../../Minecraft.World/net.minecraft.world.level.tile.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool HasAnyTrackedLeaderboardProgress(StatsCounter *statsCounter)
|
||||
{
|
||||
if (statsCounter == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int difficulty = 0; difficulty < 4; ++difficulty)
|
||||
{
|
||||
if (statsCounter->getValue(Stats::walkOneM, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::fallOneM, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::minecartOneM, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::boatOneM, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::dirt->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::stoneBrick->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::sand->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::rock->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::gravel->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::clay->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::obsidian->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::itemsCollected[Item::egg->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::crops_Id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::mushroom1_Id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::blocksMined[Tile::reeds_Id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::cowsMilked, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::itemsCollected[Tile::pumpkin->id], difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsZombie, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsSkeleton, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsCreeper, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsSpider, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsSpiderJockey, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsZombiePigman, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsNetherZombiePigman, difficulty) > 0
|
||||
|| statsCounter->getValue(Stats::killsSlime, difficulty) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::wstring TrimWhitespace(const std::wstring &text)
|
||||
{
|
||||
size_t start = 0;
|
||||
while (start < text.length() && iswspace(text[start]))
|
||||
{
|
||||
++start;
|
||||
}
|
||||
|
||||
size_t end = text.length();
|
||||
while (end > start && iswspace(text[end - 1]))
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
return text.substr(start, end - start);
|
||||
}
|
||||
|
||||
static bool IsBooleanText(const std::wstring &text)
|
||||
{
|
||||
return (_wcsicmp(text.c_str(), L"false") == 0) || (_wcsicmp(text.c_str(), L"true") == 0);
|
||||
}
|
||||
|
||||
static std::wstring ToWideName(const char *text)
|
||||
{
|
||||
if (text == NULL || text[0] == 0)
|
||||
{
|
||||
return L"";
|
||||
}
|
||||
|
||||
wchar_t wideName[XUSER_NAME_SIZE + 1];
|
||||
ZeroMemory(wideName, sizeof(wideName));
|
||||
MultiByteToWideChar(CP_ACP, 0, text, -1, wideName, XUSER_NAME_SIZE + 1);
|
||||
wideName[XUSER_NAME_SIZE] = 0;
|
||||
return wideName;
|
||||
}
|
||||
|
||||
static int GetLocalPad()
|
||||
{
|
||||
int iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
iPad = ProfileManager.GetLockedProfile();
|
||||
}
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
iPad = 0;
|
||||
}
|
||||
return iPad;
|
||||
}
|
||||
|
||||
static PlayerUID GetLocalPlayerUID(int iPad)
|
||||
{
|
||||
PlayerUID uid = INVALID_XUID;
|
||||
ProfileManager.GetXUID(iPad, &uid, true);
|
||||
if (uid == INVALID_XUID)
|
||||
{
|
||||
ProfileManager.GetXUID(iPad, &uid, false);
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
|
||||
static std::wstring GetLocalDisplayName(int iPad)
|
||||
{
|
||||
std::wstring displayName = TrimWhitespace(ProfileManager.GetDisplayName(iPad));
|
||||
|
||||
if (displayName.empty() || IsBooleanText(displayName))
|
||||
{
|
||||
displayName = TrimWhitespace(ToWideName(ProfileManager.GetGamertag(iPad)));
|
||||
}
|
||||
|
||||
if (displayName.empty() || IsBooleanText(displayName))
|
||||
{
|
||||
displayName = L"Player";
|
||||
}
|
||||
|
||||
if (displayName.length() > XUSER_NAME_SIZE)
|
||||
{
|
||||
displayName.resize(XUSER_NAME_SIZE);
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
static StatsCounter *GetLocalStatsCounter(int iPad)
|
||||
{
|
||||
Minecraft *minecraft = Minecraft::GetInstance();
|
||||
if (minecraft == NULL || iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StatsCounter *statsCounter = minecraft->stats[iPad];
|
||||
if (statsCounter == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!app.GetGameStarted())
|
||||
{
|
||||
if (!HasAnyTrackedLeaderboardProgress(statsCounter))
|
||||
{
|
||||
void *profileData = ProfileManager.GetGameDefinedProfileData(iPad);
|
||||
if (profileData != NULL)
|
||||
{
|
||||
statsCounter->clear();
|
||||
statsCounter->parse(profileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return statsCounter;
|
||||
}
|
||||
|
||||
static unsigned int GetStatValue(StatsCounter *statsCounter, Stat *stat, int difficulty)
|
||||
{
|
||||
if (statsCounter == NULL || stat == NULL || difficulty < 0 || difficulty > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return statsCounter->getValue(stat, (unsigned int)difficulty);
|
||||
}
|
||||
|
||||
static unsigned int GetBlockValue(StatsCounter *statsCounter, Tile *tile, int difficulty)
|
||||
{
|
||||
if (tile == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return GetStatValue(statsCounter, Stats::blocksMined[tile->id], difficulty);
|
||||
}
|
||||
|
||||
static unsigned int GetCollectedItemValue(StatsCounter *statsCounter, Item *item, int difficulty)
|
||||
{
|
||||
if (item == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return GetStatValue(statsCounter, Stats::itemsCollected[item->id], difficulty);
|
||||
}
|
||||
|
||||
static unsigned int GetZombiePigmanKills(StatsCounter *statsCounter, int difficulty)
|
||||
{
|
||||
unsigned long long total = (unsigned long long)GetStatValue(statsCounter, Stats::killsZombiePigman, difficulty)
|
||||
+ (unsigned long long)GetStatValue(statsCounter, Stats::killsNetherZombiePigman, difficulty);
|
||||
return (total > 0xFFFFFFFFULL) ? 0xFFFFFFFFU : (unsigned int)total;
|
||||
}
|
||||
|
||||
static unsigned short GetStatsSize(LeaderboardManager::EStatsType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LeaderboardManager::eStatsType_Travelling:
|
||||
return 4;
|
||||
|
||||
case LeaderboardManager::eStatsType_Mining:
|
||||
return 7;
|
||||
|
||||
case LeaderboardManager::eStatsType_Farming:
|
||||
return 6;
|
||||
|
||||
case LeaderboardManager::eStatsType_Kills:
|
||||
return 7;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetColumn(LeaderboardManager::ReadScore &score, unsigned int columnIndex, unsigned long value, unsigned long long &total)
|
||||
{
|
||||
if (columnIndex >= LeaderboardManager::ReadScore::STATSDATA_MAX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
score.m_statsData[columnIndex] = value;
|
||||
total += value;
|
||||
}
|
||||
|
||||
static unsigned long ClampToUnsignedLong(unsigned long long value)
|
||||
{
|
||||
return (value > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL : (unsigned long)value;
|
||||
}
|
||||
|
||||
static const char *GetStatsTypeName(LeaderboardManager::EStatsType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LeaderboardManager::eStatsType_Travelling:
|
||||
return "Travelling";
|
||||
case LeaderboardManager::eStatsType_Mining:
|
||||
return "Mining";
|
||||
case LeaderboardManager::eStatsType_Farming:
|
||||
return "Farming";
|
||||
case LeaderboardManager::eStatsType_Kills:
|
||||
return "Kills";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void SetTravellingColumns(LeaderboardManager::ReadScore &score, StatsCounter *statsCounter, int difficulty, unsigned long long &total)
|
||||
{
|
||||
SetColumn(score, 0, GetStatValue(statsCounter, Stats::walkOneM, difficulty), total);
|
||||
SetColumn(score, 1, GetStatValue(statsCounter, Stats::fallOneM, difficulty), total);
|
||||
SetColumn(score, 2, GetStatValue(statsCounter, Stats::minecartOneM, difficulty), total);
|
||||
SetColumn(score, 3, GetStatValue(statsCounter, Stats::boatOneM, difficulty), total);
|
||||
}
|
||||
|
||||
static unsigned long long GetTravellingTotalForDifficulty(StatsCounter *statsCounter, int difficulty)
|
||||
{
|
||||
if (difficulty < 0 || difficulty > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long total = 0;
|
||||
total += GetStatValue(statsCounter, Stats::walkOneM, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::fallOneM, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::minecartOneM, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::boatOneM, difficulty);
|
||||
return total;
|
||||
}
|
||||
|
||||
static void SetMiningColumns(LeaderboardManager::ReadScore &score, StatsCounter *statsCounter, int difficulty, unsigned long long &total)
|
||||
{
|
||||
SetColumn(score, 0, GetBlockValue(statsCounter, Tile::dirt, difficulty), total);
|
||||
SetColumn(score, 1, GetBlockValue(statsCounter, Tile::stoneBrick, difficulty), total);
|
||||
SetColumn(score, 2, GetBlockValue(statsCounter, Tile::sand, difficulty), total);
|
||||
SetColumn(score, 3, GetBlockValue(statsCounter, Tile::rock, difficulty), total);
|
||||
SetColumn(score, 4, GetBlockValue(statsCounter, Tile::gravel, difficulty), total);
|
||||
SetColumn(score, 5, GetBlockValue(statsCounter, Tile::clay, difficulty), total);
|
||||
SetColumn(score, 6, GetBlockValue(statsCounter, Tile::obsidian, difficulty), total);
|
||||
}
|
||||
|
||||
static unsigned long long GetMiningTotalForDifficulty(StatsCounter *statsCounter, int difficulty)
|
||||
{
|
||||
if (difficulty < 0 || difficulty > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long total = 0;
|
||||
total += GetBlockValue(statsCounter, Tile::dirt, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::stoneBrick, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::sand, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::rock, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::gravel, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::clay, difficulty);
|
||||
total += GetBlockValue(statsCounter, Tile::obsidian, difficulty);
|
||||
return total;
|
||||
}
|
||||
|
||||
static void SetFarmingColumns(LeaderboardManager::ReadScore &score, StatsCounter *statsCounter, int difficulty, unsigned long long &total)
|
||||
{
|
||||
SetColumn(score, 0, GetCollectedItemValue(statsCounter, Item::egg, difficulty), total);
|
||||
SetColumn(score, 1, GetStatValue(statsCounter, Stats::blocksMined[Tile::crops_Id], difficulty), total);
|
||||
SetColumn(score, 2, GetStatValue(statsCounter, Stats::blocksMined[Tile::mushroom1_Id], difficulty), total);
|
||||
SetColumn(score, 3, GetStatValue(statsCounter, Stats::blocksMined[Tile::reeds_Id], difficulty), total);
|
||||
SetColumn(score, 4, GetStatValue(statsCounter, Stats::cowsMilked, difficulty), total);
|
||||
SetColumn(score, 5, GetStatValue(statsCounter, Stats::itemsCollected[Tile::pumpkin->id], difficulty), total);
|
||||
}
|
||||
|
||||
static unsigned long long GetFarmingTotalForDifficulty(StatsCounter *statsCounter, int difficulty)
|
||||
{
|
||||
if (difficulty < 0 || difficulty > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long total = 0;
|
||||
total += GetCollectedItemValue(statsCounter, Item::egg, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::blocksMined[Tile::crops_Id], difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::blocksMined[Tile::mushroom1_Id], difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::blocksMined[Tile::reeds_Id], difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::cowsMilked, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::itemsCollected[Tile::pumpkin->id], difficulty);
|
||||
return total;
|
||||
}
|
||||
|
||||
static void SetKillsColumns(LeaderboardManager::ReadScore &score, StatsCounter *statsCounter, int difficulty, unsigned long long &total)
|
||||
{
|
||||
SetColumn(score, 0, GetStatValue(statsCounter, Stats::killsZombie, difficulty), total);
|
||||
SetColumn(score, 1, GetStatValue(statsCounter, Stats::killsSkeleton, difficulty), total);
|
||||
SetColumn(score, 2, GetStatValue(statsCounter, Stats::killsCreeper, difficulty), total);
|
||||
SetColumn(score, 3, GetStatValue(statsCounter, Stats::killsSpider, difficulty), total);
|
||||
SetColumn(score, 4, GetStatValue(statsCounter, Stats::killsSpiderJockey, difficulty), total);
|
||||
SetColumn(score, 5, GetZombiePigmanKills(statsCounter, difficulty), total);
|
||||
SetColumn(score, 6, GetStatValue(statsCounter, Stats::killsSlime, difficulty), total);
|
||||
}
|
||||
|
||||
static unsigned long long GetKillsTotalForDifficulty(StatsCounter *statsCounter, int difficulty)
|
||||
{
|
||||
if (difficulty < 0 || difficulty > 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long total = 0;
|
||||
total += GetStatValue(statsCounter, Stats::killsZombie, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::killsSkeleton, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::killsCreeper, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::killsSpider, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::killsSpiderJockey, difficulty);
|
||||
total += GetZombiePigmanKills(statsCounter, difficulty);
|
||||
total += GetStatValue(statsCounter, Stats::killsSlime, difficulty);
|
||||
return total;
|
||||
}
|
||||
|
||||
static bool SetColumnsForType(LeaderboardManager::ReadScore &score, StatsCounter *statsCounter, int difficulty, LeaderboardManager::EStatsType type, unsigned long long &total)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LeaderboardManager::eStatsType_Travelling:
|
||||
SetTravellingColumns(score, statsCounter, difficulty, total);
|
||||
return true;
|
||||
|
||||
case LeaderboardManager::eStatsType_Mining:
|
||||
SetMiningColumns(score, statsCounter, difficulty, total);
|
||||
return true;
|
||||
|
||||
case LeaderboardManager::eStatsType_Farming:
|
||||
SetFarmingColumns(score, statsCounter, difficulty, total);
|
||||
return true;
|
||||
|
||||
case LeaderboardManager::eStatsType_Kills:
|
||||
SetKillsColumns(score, statsCounter, difficulty, total);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long long GetTypeTotalForDifficulty(StatsCounter *statsCounter, int difficulty, LeaderboardManager::EStatsType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LeaderboardManager::eStatsType_Travelling:
|
||||
return GetTravellingTotalForDifficulty(statsCounter, difficulty);
|
||||
|
||||
case LeaderboardManager::eStatsType_Mining:
|
||||
return GetMiningTotalForDifficulty(statsCounter, difficulty);
|
||||
|
||||
case LeaderboardManager::eStatsType_Farming:
|
||||
return GetFarmingTotalForDifficulty(statsCounter, difficulty);
|
||||
|
||||
case LeaderboardManager::eStatsType_Kills:
|
||||
return GetKillsTotalForDifficulty(statsCounter, difficulty);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void DebugDumpZeroRead(StatsCounter *statsCounter, int iPad, int selectedDifficulty, LeaderboardManager::EStatsType type, unsigned long long selectedTotal)
|
||||
{
|
||||
if (selectedTotal != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long totals[4];
|
||||
for (int d = 0; d < 4; ++d)
|
||||
{
|
||||
totals[d] = GetTypeTotalForDifficulty(statsCounter, d, type);
|
||||
}
|
||||
|
||||
app.DebugPrintf(
|
||||
"[Win64 LB] %s row is zero (pad=%d selectedDiff=%d canRecord=%d gameStarted=%d) totals[p/e/n/h]=%I64u/%I64u/%I64u/%I64u\n",
|
||||
GetStatsTypeName(type),
|
||||
iPad,
|
||||
selectedDifficulty,
|
||||
app.CanRecordStatsAndAchievements() ? 1 : 0,
|
||||
app.GetGameStarted() ? 1 : 0,
|
||||
totals[0],
|
||||
totals[1],
|
||||
totals[2],
|
||||
totals[3]);
|
||||
}
|
||||
|
||||
static bool PopulateLocalReadScore(LeaderboardManager::ReadScore &score, int difficulty, LeaderboardManager::EStatsType type)
|
||||
{
|
||||
if (difficulty < 0 || difficulty > 3 || type < LeaderboardManager::eStatsType_Travelling || type >= LeaderboardManager::eStatsType_MAX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int iPad = GetLocalPad();
|
||||
StatsCounter *statsCounter = GetLocalStatsCounter(iPad);
|
||||
|
||||
score.m_uid = GetLocalPlayerUID(iPad);
|
||||
score.m_rank = 1;
|
||||
score.m_name = GetLocalDisplayName(iPad);
|
||||
score.m_totalScore = 0;
|
||||
score.m_statsSize = GetStatsSize(type);
|
||||
for (unsigned int i = 0; i < LeaderboardManager::ReadScore::STATSDATA_MAX; ++i)
|
||||
{
|
||||
score.m_statsData[i] = 0;
|
||||
}
|
||||
score.m_idsErrorMessage = 0;
|
||||
|
||||
unsigned long long totalScore = 0;
|
||||
if (!SetColumnsForType(score, statsCounter, difficulty, type, totalScore))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (totalScore == 0)
|
||||
{
|
||||
unsigned long long bestTotal = 0;
|
||||
int bestDifficulty = difficulty;
|
||||
for (int d = 0; d < 4; ++d)
|
||||
{
|
||||
unsigned long long altTotal = GetTypeTotalForDifficulty(statsCounter, d, type);
|
||||
if (altTotal > bestTotal)
|
||||
{
|
||||
bestTotal = altTotal;
|
||||
bestDifficulty = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestTotal > 0 && bestDifficulty != difficulty)
|
||||
{
|
||||
totalScore = 0;
|
||||
SetColumnsForType(score, statsCounter, bestDifficulty, type, totalScore);
|
||||
app.DebugPrintf("[Win64 LB] %s fallback used alternate difficulty %d for selected difficulty %d (pad=%d)\n", GetStatsTypeName(type), bestDifficulty, difficulty, iPad);
|
||||
}
|
||||
}
|
||||
|
||||
DebugDumpZeroRead(statsCounter, iPad, difficulty, type, totalScore);
|
||||
|
||||
score.m_totalScore = ClampToUnsignedLong(totalScore);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaderboardManager *LeaderboardManager::m_instance = new WindowsLeaderboardManager();
|
||||
|
||||
void WindowsLeaderboardManager::Tick() {}
|
||||
|
||||
bool WindowsLeaderboardManager::OpenSession()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowsLeaderboardManager::CloseSession() {}
|
||||
|
||||
void WindowsLeaderboardManager::DeleteSession() {}
|
||||
|
||||
bool WindowsLeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(viewCount);
|
||||
|
||||
if (views != NULL)
|
||||
{
|
||||
delete [] views;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsLeaderboardManager::ReadStats_Friends(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount)
|
||||
{
|
||||
if (!LeaderboardManager::ReadStats_Friends(callback, difficulty, type, myUID, startIndex, readCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadStats_Local(callback, difficulty, type, startIndex, readCount);
|
||||
}
|
||||
|
||||
bool WindowsLeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount)
|
||||
{
|
||||
if (!LeaderboardManager::ReadStats_MyScore(callback, difficulty, type, myUID, readCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadStats_Local(callback, difficulty, type, 1, readCount);
|
||||
}
|
||||
|
||||
bool WindowsLeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *callback, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount)
|
||||
{
|
||||
if (!LeaderboardManager::ReadStats_TopRank(callback, difficulty, type, startIndex, readCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadStats_Local(callback, difficulty, type, startIndex, readCount);
|
||||
}
|
||||
|
||||
void WindowsLeaderboardManager::FlushStats() {}
|
||||
|
||||
void WindowsLeaderboardManager::CancelOperation()
|
||||
{
|
||||
zeroReadParameters();
|
||||
m_readListener = NULL;
|
||||
}
|
||||
|
||||
bool WindowsLeaderboardManager::isIdle()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsLeaderboardManager::ReadStats_Local(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(readCount);
|
||||
|
||||
if (listener == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewOut view;
|
||||
view.m_numQueries = 0;
|
||||
view.m_queries = NULL;
|
||||
|
||||
ReadScore localScore;
|
||||
|
||||
if (startIndex <= 1 && PopulateLocalReadScore(localScore, difficulty, type))
|
||||
{
|
||||
view.m_numQueries = 1;
|
||||
view.m_queries = &localScore;
|
||||
listener->OnStatsReadComplete(eStatsReturn_Success, 1, view);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (difficulty >= 0 && difficulty <= 3 && type >= eStatsType_Travelling && type < eStatsType_MAX)
|
||||
{
|
||||
listener->OnStatsReadComplete(eStatsReturn_Success, 1, view);
|
||||
return true;
|
||||
}
|
||||
|
||||
listener->OnStatsReadComplete(eStatsReturn_NoResults, 0, view);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -5,32 +5,35 @@
|
|||
class WindowsLeaderboardManager : public LeaderboardManager
|
||||
{
|
||||
public:
|
||||
virtual void Tick() {}
|
||||
virtual void Tick() override;
|
||||
|
||||
//Open a session
|
||||
virtual bool OpenSession() { return true; }
|
||||
virtual bool OpenSession() override;
|
||||
|
||||
//Close a session
|
||||
virtual void CloseSession() {}
|
||||
virtual void CloseSession() override;
|
||||
|
||||
//Delete a session
|
||||
virtual void DeleteSession() {}
|
||||
virtual void DeleteSession() override;
|
||||
|
||||
//Write the given stats
|
||||
//This is called synchronously and will not free any memory allocated for views when it is done
|
||||
|
||||
virtual bool WriteStats(unsigned int viewCount, ViewIn views) { return false; }
|
||||
virtual bool WriteStats(unsigned int viewCount, ViewIn views) override;
|
||||
|
||||
virtual bool ReadStats_Friends(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID) { return false; }
|
||||
virtual bool ReadStats_MyScore(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount) { return false; }
|
||||
virtual bool ReadStats_TopRank(LeaderboardReadListener *callback, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount) { return false; }
|
||||
virtual bool ReadStats_Friends(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount) override;
|
||||
virtual bool ReadStats_MyScore(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount) override;
|
||||
virtual bool ReadStats_TopRank(LeaderboardReadListener *callback, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount) override;
|
||||
|
||||
//Perform a flush of the stats
|
||||
virtual void FlushStats() {}
|
||||
virtual void FlushStats() override;
|
||||
|
||||
//Cancel the current operation
|
||||
virtual void CancelOperation() {}
|
||||
virtual void CancelOperation() override;
|
||||
|
||||
//Is the leaderboard manager idle.
|
||||
virtual bool isIdle() { return true; }
|
||||
virtual bool isIdle() override;
|
||||
|
||||
private:
|
||||
bool ReadStats_Local(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
SOCKET WinsockNetLayer::s_listenSocket = INVALID_SOCKET;
|
||||
SOCKET WinsockNetLayer::s_hostConnectionSocket = INVALID_SOCKET;
|
||||
HANDLE WinsockNetLayer::s_acceptThread = NULL;
|
||||
HANDLE WinsockNetLayer::s_ioThread = NULL;
|
||||
HANDLE WinsockNetLayer::s_clientRecvThread = NULL;
|
||||
|
||||
bool WinsockNetLayer::s_isHost = false;
|
||||
|
|
@ -25,7 +26,7 @@ BYTE WinsockNetLayer::s_nextSmallId = 1;
|
|||
CRITICAL_SECTION WinsockNetLayer::s_sendLock;
|
||||
CRITICAL_SECTION WinsockNetLayer::s_connectionsLock;
|
||||
|
||||
Win64RemoteConnection WinsockNetLayer::s_connections[WIN64_NET_MAX_CLIENTS + 1];
|
||||
std::vector<Win64RemoteConnection> WinsockNetLayer::s_connections;
|
||||
|
||||
SOCKET WinsockNetLayer::s_advertiseSock = INVALID_SOCKET;
|
||||
HANDLE WinsockNetLayer::s_advertiseThread = NULL;
|
||||
|
|
@ -35,6 +36,7 @@ CRITICAL_SECTION WinsockNetLayer::s_advertiseLock;
|
|||
int WinsockNetLayer::s_hostGamePort = WIN64_NET_DEFAULT_PORT;
|
||||
|
||||
SOCKET WinsockNetLayer::s_discoverySock = INVALID_SOCKET;
|
||||
SOCKET WinsockNetLayer::s_discoveryLegacySock = INVALID_SOCKET;
|
||||
HANDLE WinsockNetLayer::s_discoveryThread = NULL;
|
||||
volatile bool WinsockNetLayer::s_discovering = false;
|
||||
CRITICAL_SECTION WinsockNetLayer::s_discoveryLock;
|
||||
|
|
@ -50,7 +52,13 @@ CRITICAL_SECTION WinsockNetLayer::s_freeSmallIdLock;
|
|||
std::vector<BYTE> WinsockNetLayer::s_freeSmallIds;
|
||||
|
||||
CRITICAL_SECTION WinsockNetLayer::s_earlyDataLock;
|
||||
std::vector<BYTE> WinsockNetLayer::s_earlyDataBuffers[WIN64_NET_MAX_CLIENTS + 1];
|
||||
std::vector<std::vector<BYTE> > WinsockNetLayer::s_earlyDataBuffers;
|
||||
|
||||
HANDLE WinsockNetLayer::s_asyncJoinThread = NULL;
|
||||
volatile WinsockNetLayer::JoinResult WinsockNetLayer::s_asyncJoinResult = WinsockNetLayer::JOIN_FAILED;
|
||||
volatile bool WinsockNetLayer::s_asyncJoinActive = false;
|
||||
char WinsockNetLayer::s_asyncJoinIP[256] = {};
|
||||
int WinsockNetLayer::s_asyncJoinPort = 0;
|
||||
|
||||
bool g_Win64MultiplayerHost = false;
|
||||
bool g_Win64MultiplayerJoin = false;
|
||||
|
|
@ -65,6 +73,16 @@ int g_ServerMaxPlayers = MINECRAFT_NET_MAX_PLAYERS;
|
|||
int g_ServerMaxPlayers = 8;
|
||||
#endif
|
||||
|
||||
size_t WinsockNetLayer::GetConnectionSlotCount()
|
||||
{
|
||||
int configured = g_ServerMaxPlayers;
|
||||
if (configured < 1)
|
||||
configured = 1;
|
||||
if (configured > 255)
|
||||
configured = 255;
|
||||
return (size_t)configured;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::Initialize()
|
||||
{
|
||||
if (s_initialized) return true;
|
||||
|
|
@ -86,13 +104,27 @@ bool WinsockNetLayer::Initialize()
|
|||
InitializeCriticalSection(&s_freeSmallIdLock);
|
||||
InitializeCriticalSection(&s_earlyDataLock);
|
||||
|
||||
for (int i = 0; i < WIN64_NET_MAX_CLIENTS + 1; i++)
|
||||
size_t slotCount = GetConnectionSlotCount();
|
||||
s_connections.clear();
|
||||
s_connections.resize(slotCount);
|
||||
s_earlyDataBuffers.clear();
|
||||
s_earlyDataBuffers.resize(slotCount);
|
||||
|
||||
for (size_t i = 0; i < slotCount; i++)
|
||||
{
|
||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||
s_connections[i].smallId = 0;
|
||||
s_connections[i].recvThread = NULL;
|
||||
s_connections[i].smallId = (BYTE)i;
|
||||
s_connections[i].active = false;
|
||||
InitializeCriticalSection(&s_connections[i].sendLock);
|
||||
s_connections[i].recvBuffer = NULL;
|
||||
s_connections[i].recvBufferUsed = 0;
|
||||
s_connections[i].recvBufferSize = 0;
|
||||
s_connections[i].currentPacketSize = 0;
|
||||
s_connections[i].readingHeader = true;
|
||||
s_connections[i].sendBuffer = NULL;
|
||||
s_connections[i].sendBufferUsed = 0;
|
||||
s_connections[i].sendBufferSize = 0;
|
||||
InitializeCriticalSection(&s_connections[i].sendBufLock);
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
|
@ -106,6 +138,7 @@ bool WinsockNetLayer::Initialize()
|
|||
|
||||
void WinsockNetLayer::Shutdown()
|
||||
{
|
||||
CancelJoinGame();
|
||||
StopAdvertising();
|
||||
StopDiscovery();
|
||||
|
||||
|
|
@ -125,7 +158,7 @@ void WinsockNetLayer::Shutdown()
|
|||
}
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
for (int i = 0; i < WIN64_NET_MAX_CLIENTS + 1; i++)
|
||||
for (size_t i = 0; i < s_connections.size(); i++)
|
||||
{
|
||||
s_connections[i].active = false;
|
||||
if (s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||
|
|
@ -133,16 +166,30 @@ void WinsockNetLayer::Shutdown()
|
|||
closesocket(s_connections[i].tcpSocket);
|
||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||
}
|
||||
if (s_connections[i].recvThread != NULL)
|
||||
if (s_connections[i].recvBuffer != NULL)
|
||||
{
|
||||
WaitForSingleObject(s_connections[i].recvThread, 2000);
|
||||
CloseHandle(s_connections[i].recvThread);
|
||||
s_connections[i].recvThread = NULL;
|
||||
free(s_connections[i].recvBuffer);
|
||||
s_connections[i].recvBuffer = NULL;
|
||||
}
|
||||
if (s_connections[i].sendBuffer != NULL)
|
||||
{
|
||||
free(s_connections[i].sendBuffer);
|
||||
s_connections[i].sendBuffer = NULL;
|
||||
}
|
||||
DeleteCriticalSection(&s_connections[i].sendBufLock);
|
||||
DeleteCriticalSection(&s_connections[i].sendLock);
|
||||
}
|
||||
s_connections.clear();
|
||||
s_earlyDataBuffers.clear();
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
if (s_ioThread != NULL)
|
||||
{
|
||||
WaitForSingleObject(s_ioThread, 3000);
|
||||
CloseHandle(s_ioThread);
|
||||
s_ioThread = NULL;
|
||||
}
|
||||
|
||||
if (s_acceptThread != NULL)
|
||||
{
|
||||
WaitForSingleObject(s_acceptThread, 2000);
|
||||
|
|
@ -247,6 +294,7 @@ bool WinsockNetLayer::HostGame(int port)
|
|||
s_active = true;
|
||||
s_connected = true;
|
||||
|
||||
s_ioThread = CreateThread(NULL, 0, IOThreadProc, NULL, 0, NULL);
|
||||
s_acceptThread = CreateThread(NULL, 0, AcceptThreadProc, NULL, 0, NULL);
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Hosting on port %d\n", port);
|
||||
|
|
@ -391,6 +439,59 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::BeginJoinGame(const char *ip, int port)
|
||||
{
|
||||
if (s_asyncJoinActive)
|
||||
return false;
|
||||
|
||||
CancelJoinGame();
|
||||
|
||||
strncpy_s(s_asyncJoinIP, sizeof(s_asyncJoinIP), ip, _TRUNCATE);
|
||||
s_asyncJoinPort = port;
|
||||
s_asyncJoinResult = JOIN_IN_PROGRESS;
|
||||
s_asyncJoinActive = true;
|
||||
|
||||
s_asyncJoinThread = CreateThread(NULL, 0, AsyncJoinThreadProc, NULL, 0, NULL);
|
||||
if (s_asyncJoinThread == NULL)
|
||||
{
|
||||
s_asyncJoinActive = false;
|
||||
s_asyncJoinResult = JOIN_FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WinsockNetLayer::JoinResult WinsockNetLayer::PollJoinResult()
|
||||
{
|
||||
return s_asyncJoinResult;
|
||||
}
|
||||
|
||||
void WinsockNetLayer::CancelJoinGame()
|
||||
{
|
||||
if (s_asyncJoinThread != NULL)
|
||||
{
|
||||
s_asyncJoinActive = false;
|
||||
WaitForSingleObject(s_asyncJoinThread, 5000);
|
||||
CloseHandle(s_asyncJoinThread);
|
||||
s_asyncJoinThread = NULL;
|
||||
}
|
||||
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET && !s_connected)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::AsyncJoinThreadProc(LPVOID param)
|
||||
{
|
||||
bool result = JoinGame(s_asyncJoinIP, s_asyncJoinPort);
|
||||
s_asyncJoinResult = result ? JOIN_SUCCESS : JOIN_FAILED;
|
||||
s_asyncJoinActive = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
|
||||
{
|
||||
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false;
|
||||
|
|
@ -426,23 +527,59 @@ bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
|
|||
bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void *data, int dataSize)
|
||||
{
|
||||
if (!s_active) return false;
|
||||
if (dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE || data == NULL) return false;
|
||||
|
||||
if (s_isHost)
|
||||
{
|
||||
if ((size_t)targetSmallId >= s_connections.size()) return false;
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
if (targetSmallId >= WIN64_NET_MAX_CLIENTS + 1 || !s_connections[targetSmallId].active)
|
||||
if (!s_connections[targetSmallId].active)
|
||||
{
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
return false;
|
||||
}
|
||||
SOCKET sock = s_connections[targetSmallId].tcpSocket;
|
||||
CRITICAL_SECTION *pLock = &s_connections[targetSmallId].sendLock;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
EnterCriticalSection(pLock);
|
||||
bool result = SendOnSocket(sock, data, dataSize);
|
||||
LeaveCriticalSection(pLock);
|
||||
return result;
|
||||
BYTE header[4];
|
||||
header[0] = (BYTE)((dataSize >> 24) & 0xFF);
|
||||
header[1] = (BYTE)((dataSize >> 16) & 0xFF);
|
||||
header[2] = (BYTE)((dataSize >> 8) & 0xFF);
|
||||
header[3] = (BYTE)(dataSize & 0xFF);
|
||||
|
||||
int totalNeeded = 4 + dataSize;
|
||||
|
||||
EnterCriticalSection(&s_connections[targetSmallId].sendBufLock);
|
||||
|
||||
if (s_connections[targetSmallId].sendBufferUsed + totalNeeded > WIN64_NET_MAX_SEND_QUEUE)
|
||||
{
|
||||
LeaveCriticalSection(&s_connections[targetSmallId].sendBufLock);
|
||||
app.DebugPrintf("Win64 LAN: Send queue overflow for smallId=%d, disconnecting\n", targetSmallId);
|
||||
CloseConnectionBySmallId(targetSmallId);
|
||||
return false;
|
||||
}
|
||||
|
||||
int space = s_connections[targetSmallId].sendBufferSize - s_connections[targetSmallId].sendBufferUsed;
|
||||
if (space < totalNeeded)
|
||||
{
|
||||
int newSize = s_connections[targetSmallId].sendBufferUsed + totalNeeded + 65536;
|
||||
BYTE *newBuf = (BYTE *)realloc(s_connections[targetSmallId].sendBuffer, newSize);
|
||||
if (newBuf == NULL)
|
||||
{
|
||||
LeaveCriticalSection(&s_connections[targetSmallId].sendBufLock);
|
||||
return false;
|
||||
}
|
||||
s_connections[targetSmallId].sendBuffer = newBuf;
|
||||
s_connections[targetSmallId].sendBufferSize = newSize;
|
||||
}
|
||||
|
||||
memcpy(s_connections[targetSmallId].sendBuffer + s_connections[targetSmallId].sendBufferUsed, header, 4);
|
||||
s_connections[targetSmallId].sendBufferUsed += 4;
|
||||
memcpy(s_connections[targetSmallId].sendBuffer + s_connections[targetSmallId].sendBufferUsed, data, dataSize);
|
||||
s_connections[targetSmallId].sendBufferUsed += dataSize;
|
||||
|
||||
LeaveCriticalSection(&s_connections[targetSmallId].sendBufLock);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -456,7 +593,7 @@ bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void *data, int da
|
|||
SOCKET WinsockNetLayer::GetSocketForSmallId(BYTE smallId)
|
||||
{
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
if (smallId < WIN64_NET_MAX_CLIENTS + 1 && s_connections[smallId].active)
|
||||
if ((size_t)smallId < s_connections.size() && s_connections[smallId].active)
|
||||
{
|
||||
SOCKET sock = s_connections[smallId].tcpSocket;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
|
@ -497,7 +634,7 @@ void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsig
|
|||
|
||||
if (pPlayerFrom == NULL || pPlayerTo == NULL)
|
||||
{
|
||||
if (s_isHost && fromSmallId > 0 && fromSmallId < WIN64_NET_MAX_CLIENTS + 1)
|
||||
if (s_isHost && fromSmallId > 0 && (size_t)fromSmallId < s_earlyDataBuffers.size())
|
||||
{
|
||||
EnterCriticalSection(&s_earlyDataLock);
|
||||
s_earlyDataBuffers[fromSmallId].insert(
|
||||
|
|
@ -531,7 +668,7 @@ void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsig
|
|||
void WinsockNetLayer::FlushPendingData()
|
||||
{
|
||||
EnterCriticalSection(&s_earlyDataLock);
|
||||
for (int i = 1; i < WIN64_NET_MAX_CLIENTS + 1; i++)
|
||||
for (size_t i = 1; i < s_earlyDataBuffers.size(); i++)
|
||||
{
|
||||
if (s_earlyDataBuffers[i].empty()) continue;
|
||||
|
||||
|
|
@ -563,6 +700,11 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
|||
int noDelay = 1;
|
||||
setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||
|
||||
int sndbuf = 131072;
|
||||
setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(sndbuf));
|
||||
int rcvbuf = 131072;
|
||||
setsockopt(clientSocket, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
extern QNET_STATE _iQNetStubState;
|
||||
if (_iQNetStubState != QNET_STATE_GAME_PLAY)
|
||||
{
|
||||
|
|
@ -591,6 +733,13 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
|||
}
|
||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||
|
||||
if ((size_t)assignedSmallId >= s_connections.size() || assignedSmallId >= IQNet::GetPlayerCapacity())
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Invalid smallId %d, rejecting\n", assignedSmallId);
|
||||
closesocket(clientSocket);
|
||||
continue;
|
||||
}
|
||||
|
||||
BYTE assignBuf[1] = { assignedSmallId };
|
||||
int sent = send(clientSocket, (const char *)assignBuf, 1, 0);
|
||||
if (sent != 1)
|
||||
|
|
@ -600,18 +749,31 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
|||
continue;
|
||||
}
|
||||
|
||||
u_long nonBlocking = 1;
|
||||
ioctlsocket(clientSocket, FIONBIO, &nonBlocking);
|
||||
|
||||
Win64RemoteConnection &conn = s_connections[assignedSmallId];
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
if (conn.recvThread != NULL)
|
||||
{
|
||||
WaitForSingleObject(conn.recvThread, 2000);
|
||||
CloseHandle(conn.recvThread);
|
||||
conn.recvThread = NULL;
|
||||
}
|
||||
conn.tcpSocket = clientSocket;
|
||||
conn.smallId = assignedSmallId;
|
||||
conn.active = true;
|
||||
conn.recvBufferUsed = 0;
|
||||
conn.currentPacketSize = 0;
|
||||
conn.readingHeader = true;
|
||||
if (conn.recvBuffer == NULL)
|
||||
{
|
||||
conn.recvBuffer = (BYTE *)malloc(WIN64_NET_RECV_BUFFER_SIZE);
|
||||
conn.recvBufferSize = WIN64_NET_RECV_BUFFER_SIZE;
|
||||
}
|
||||
EnterCriticalSection(&conn.sendBufLock);
|
||||
conn.sendBufferUsed = 0;
|
||||
if (conn.sendBuffer == NULL)
|
||||
{
|
||||
conn.sendBuffer = (BYTE *)malloc(WIN64_NET_SEND_BUFFER_SIZE);
|
||||
conn.sendBufferSize = WIN64_NET_SEND_BUFFER_SIZE;
|
||||
}
|
||||
LeaveCriticalSection(&conn.sendBufLock);
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId);
|
||||
|
|
@ -621,91 +783,177 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
|||
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal);
|
||||
Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false);
|
||||
|
||||
|
||||
EnterCriticalSection(&s_pendingJoinLock);
|
||||
s_pendingJoinSmallIds.push_back(assignedSmallId);
|
||||
LeaveCriticalSection(&s_pendingJoinLock);
|
||||
|
||||
DWORD *threadParam = new DWORD;
|
||||
*threadParam = assignedSmallId;
|
||||
HANDLE hThread = CreateThread(NULL, 0, RecvThreadProc, threadParam, 0, NULL);
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
s_connections[assignedSmallId].recvThread = hThread;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
|
||||
bool WinsockNetLayer::ProcessRecvData(Win64RemoteConnection &conn)
|
||||
{
|
||||
BYTE clientSmallId = (BYTE)*(DWORD *)param;
|
||||
delete (DWORD *)param;
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
if (clientSmallId >= WIN64_NET_MAX_CLIENTS + 1 || !s_connections[clientSmallId].active)
|
||||
if (conn.readingHeader)
|
||||
{
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
return 0;
|
||||
}
|
||||
SOCKET sock = s_connections[clientSmallId].tcpSocket;
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
std::vector<BYTE> recvBuf;
|
||||
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
|
||||
|
||||
while (s_active)
|
||||
{
|
||||
BYTE header[4];
|
||||
if (!RecvExact(sock, header, 4))
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (header)\n", clientSmallId);
|
||||
break;
|
||||
}
|
||||
if (conn.recvBufferUsed < 4) return false;
|
||||
|
||||
int packetSize =
|
||||
((uint32_t)header[0] << 24) |
|
||||
((uint32_t)header[1] << 16) |
|
||||
((uint32_t)header[2] << 8) |
|
||||
((uint32_t)header[3]);
|
||||
((uint32_t)conn.recvBuffer[0] << 24) |
|
||||
((uint32_t)conn.recvBuffer[1] << 16) |
|
||||
((uint32_t)conn.recvBuffer[2] << 8) |
|
||||
((uint32_t)conn.recvBuffer[3]);
|
||||
|
||||
if (packetSize <= 0 || (unsigned int)packetSize > WIN64_NET_MAX_PACKET_SIZE)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
|
||||
packetSize,
|
||||
clientSmallId,
|
||||
(int)WIN64_NET_MAX_PACKET_SIZE);
|
||||
break;
|
||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from smallId=%d\n", packetSize, conn.smallId);
|
||||
conn.active = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((int)recvBuf.size() < packetSize)
|
||||
conn.currentPacketSize = packetSize;
|
||||
conn.readingHeader = false;
|
||||
|
||||
memmove(conn.recvBuffer, conn.recvBuffer + 4, conn.recvBufferUsed - 4);
|
||||
conn.recvBufferUsed -= 4;
|
||||
|
||||
if (conn.recvBufferSize < packetSize)
|
||||
{
|
||||
recvBuf.resize(packetSize);
|
||||
app.DebugPrintf("Win64 LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId);
|
||||
int newSize = packetSize + 4096;
|
||||
BYTE *newBuf = (BYTE *)realloc(conn.recvBuffer, newSize);
|
||||
if (newBuf == NULL)
|
||||
{
|
||||
conn.active = false;
|
||||
return false;
|
||||
}
|
||||
conn.recvBuffer = newBuf;
|
||||
conn.recvBufferSize = newSize;
|
||||
}
|
||||
|
||||
if (!RecvExact(sock, &recvBuf[0], packetSize))
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
|
||||
break;
|
||||
}
|
||||
|
||||
HandleDataReceived(clientSmallId, s_hostSmallId, &recvBuf[0], packetSize);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
s_connections[clientSmallId].active = false;
|
||||
if (s_connections[clientSmallId].tcpSocket != INVALID_SOCKET)
|
||||
if (conn.recvBufferUsed < conn.currentPacketSize) return false;
|
||||
|
||||
HandleDataReceived(conn.smallId, s_hostSmallId, conn.recvBuffer, conn.currentPacketSize);
|
||||
|
||||
int remaining = conn.recvBufferUsed - conn.currentPacketSize;
|
||||
if (remaining > 0)
|
||||
memmove(conn.recvBuffer, conn.recvBuffer + conn.currentPacketSize, remaining);
|
||||
conn.recvBufferUsed = remaining;
|
||||
conn.readingHeader = true;
|
||||
|
||||
return (remaining >= 4);
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::IOThreadProc(LPVOID param)
|
||||
{
|
||||
std::vector<WSAPOLLFD> pollFds;
|
||||
std::vector<BYTE> pollSmallIds;
|
||||
|
||||
while (s_active)
|
||||
{
|
||||
closesocket(s_connections[clientSmallId].tcpSocket);
|
||||
s_connections[clientSmallId].tcpSocket = INVALID_SOCKET;
|
||||
pollFds.clear();
|
||||
pollSmallIds.clear();
|
||||
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
for (size_t i = 1; i < s_connections.size(); i++)
|
||||
{
|
||||
if (s_connections[i].active && s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||
{
|
||||
WSAPOLLFD pfd;
|
||||
pfd.fd = s_connections[i].tcpSocket;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
pollFds.push_back(pfd);
|
||||
pollSmallIds.push_back((BYTE)i);
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
if (pollFds.empty())
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
int ret = WSAPoll(&pollFds[0], (ULONG)pollFds.size(), 50);
|
||||
if (ret <= 0) continue;
|
||||
|
||||
for (size_t i = 0; i < pollFds.size(); i++)
|
||||
{
|
||||
BYTE smallId = pollSmallIds[i];
|
||||
if ((size_t)smallId >= s_connections.size()) continue;
|
||||
Win64RemoteConnection &conn = s_connections[smallId];
|
||||
|
||||
if (!conn.active) continue;
|
||||
|
||||
if (pollFds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
|
||||
{
|
||||
conn.active = false;
|
||||
closesocket(conn.tcpSocket);
|
||||
conn.tcpSocket = INVALID_SOCKET;
|
||||
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back(smallId);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pollFds[i].revents & POLLIN)
|
||||
{
|
||||
while (conn.active)
|
||||
{
|
||||
int space = conn.recvBufferSize - conn.recvBufferUsed;
|
||||
if (space <= 0)
|
||||
{
|
||||
int newSize = conn.recvBufferSize + 65536;
|
||||
BYTE *newBuf = (BYTE *)realloc(conn.recvBuffer, newSize);
|
||||
if (newBuf == NULL)
|
||||
{
|
||||
conn.active = false;
|
||||
closesocket(conn.tcpSocket);
|
||||
conn.tcpSocket = INVALID_SOCKET;
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back(smallId);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
break;
|
||||
}
|
||||
conn.recvBuffer = newBuf;
|
||||
conn.recvBufferSize = newSize;
|
||||
space = newSize - conn.recvBufferUsed;
|
||||
}
|
||||
|
||||
int bytesRead = recv(conn.tcpSocket, (char *)(conn.recvBuffer + conn.recvBufferUsed), space, 0);
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
conn.recvBufferUsed += bytesRead;
|
||||
while (ProcessRecvData(conn))
|
||||
;
|
||||
}
|
||||
else if (bytesRead == 0)
|
||||
{
|
||||
conn.active = false;
|
||||
closesocket(conn.tcpSocket);
|
||||
conn.tcpSocket = INVALID_SOCKET;
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back(smallId);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
break;
|
||||
conn.active = false;
|
||||
closesocket(conn.tcpSocket);
|
||||
conn.tcpSocket = INVALID_SOCKET;
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back(smallId);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back(clientSmallId);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -746,27 +994,76 @@ bool WinsockNetLayer::PopPendingJoinSmallId(BYTE *outSmallId)
|
|||
|
||||
bool WinsockNetLayer::IsSmallIdConnected(BYTE smallId)
|
||||
{
|
||||
if (smallId >= WIN64_NET_MAX_CLIENTS + 1) return false;
|
||||
if ((size_t)smallId >= s_connections.size()) return false;
|
||||
return s_connections[smallId].active;
|
||||
}
|
||||
|
||||
void WinsockNetLayer::CloseConnectionBySmallId(BYTE smallId)
|
||||
{
|
||||
EnterCriticalSection(&s_connectionsLock);
|
||||
if (smallId < WIN64_NET_MAX_CLIENTS + 1 && s_connections[smallId].active && s_connections[smallId].tcpSocket != INVALID_SOCKET)
|
||||
if ((size_t)smallId < s_connections.size() && s_connections[smallId].active && s_connections[smallId].tcpSocket != INVALID_SOCKET)
|
||||
{
|
||||
s_connections[smallId].active = false;
|
||||
closesocket(s_connections[smallId].tcpSocket);
|
||||
s_connections[smallId].tcpSocket = INVALID_SOCKET;
|
||||
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
|
||||
}
|
||||
LeaveCriticalSection(&s_connectionsLock);
|
||||
|
||||
if ((size_t)smallId < s_connections.size())
|
||||
{
|
||||
EnterCriticalSection(&s_connections[smallId].sendBufLock);
|
||||
s_connections[smallId].sendBufferUsed = 0;
|
||||
LeaveCriticalSection(&s_connections[smallId].sendBufLock);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_earlyDataLock);
|
||||
if (smallId < WIN64_NET_MAX_CLIENTS + 1)
|
||||
if ((size_t)smallId < s_earlyDataBuffers.size())
|
||||
s_earlyDataBuffers[smallId].clear();
|
||||
LeaveCriticalSection(&s_earlyDataLock);
|
||||
}
|
||||
|
||||
void WinsockNetLayer::FlushSendBuffers()
|
||||
{
|
||||
if (!s_isHost) return;
|
||||
|
||||
for (size_t i = 0; i < s_connections.size(); i++)
|
||||
{
|
||||
if (!s_connections[i].active) continue;
|
||||
|
||||
EnterCriticalSection(&s_connections[i].sendBufLock);
|
||||
if (s_connections[i].sendBufferUsed > 0 && s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||
{
|
||||
int totalSent = 0;
|
||||
while (totalSent < s_connections[i].sendBufferUsed)
|
||||
{
|
||||
int sent = send(s_connections[i].tcpSocket,
|
||||
(const char *)(s_connections[i].sendBuffer + totalSent),
|
||||
s_connections[i].sendBufferUsed - totalSent, 0);
|
||||
if (sent == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
break;
|
||||
s_connections[i].active = false;
|
||||
EnterCriticalSection(&s_disconnectLock);
|
||||
s_disconnectedSmallIds.push_back((BYTE)i);
|
||||
LeaveCriticalSection(&s_disconnectLock);
|
||||
break;
|
||||
}
|
||||
if (sent == 0) break;
|
||||
totalSent += sent;
|
||||
}
|
||||
|
||||
int remaining = s_connections[i].sendBufferUsed - totalSent;
|
||||
if (remaining > 0)
|
||||
memmove(s_connections[i].sendBuffer, s_connections[i].sendBuffer + totalSent, remaining);
|
||||
s_connections[i].sendBufferUsed = remaining;
|
||||
}
|
||||
LeaveCriticalSection(&s_connections[i].sendBufLock);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
||||
{
|
||||
std::vector<BYTE> recvBuf;
|
||||
|
|
@ -847,7 +1144,7 @@ bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, un
|
|||
s_advertising = true;
|
||||
s_advertiseThread = CreateThread(NULL, 0, AdvertiseThreadProc, NULL, 0, NULL);
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Started advertising on UDP port %d\n", WIN64_LAN_DISCOVERY_PORT);
|
||||
app.DebugPrintf("Win64 LAN: Started advertising on UDP port %d\n", gamePort);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -895,26 +1192,39 @@ void WinsockNetLayer::UpdateAdvertiseJoinable(bool joinable)
|
|||
LeaveCriticalSection(&s_advertiseLock);
|
||||
}
|
||||
|
||||
void WinsockNetLayer::UpdateAdvertiseGameHostSettings(unsigned int settings)
|
||||
{
|
||||
EnterCriticalSection(&s_advertiseLock);
|
||||
s_advertiseData.gameHostSettings = settings;
|
||||
LeaveCriticalSection(&s_advertiseLock);
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::AdvertiseThreadProc(LPVOID param)
|
||||
{
|
||||
struct sockaddr_in broadcastAddr;
|
||||
memset(&broadcastAddr, 0, sizeof(broadcastAddr));
|
||||
broadcastAddr.sin_family = AF_INET;
|
||||
broadcastAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT);
|
||||
broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||
|
||||
while (s_advertising)
|
||||
{
|
||||
EnterCriticalSection(&s_advertiseLock);
|
||||
Win64LANBroadcast data = s_advertiseData;
|
||||
int gamePort = s_hostGamePort;
|
||||
LeaveCriticalSection(&s_advertiseLock);
|
||||
|
||||
broadcastAddr.sin_port = htons((u_short)gamePort);
|
||||
int sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0,
|
||||
(struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr));
|
||||
|
||||
if (sent == SOCKET_ERROR && s_advertising)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Broadcast sendto failed: %d\n", WSAGetLastError());
|
||||
|
||||
if (gamePort != WIN64_LAN_DISCOVERY_PORT)
|
||||
{
|
||||
broadcastAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT);
|
||||
sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0,
|
||||
(struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr));
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
|
|
@ -941,24 +1251,47 @@ bool WinsockNetLayer::StartDiscovery()
|
|||
struct sockaddr_in bindAddr;
|
||||
memset(&bindAddr, 0, sizeof(bindAddr));
|
||||
bindAddr.sin_family = AF_INET;
|
||||
bindAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT);
|
||||
bindAddr.sin_port = htons(WIN64_NET_DEFAULT_PORT);
|
||||
bindAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
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 to port %d failed: %d\n", WIN64_NET_DEFAULT_PORT, WSAGetLastError());
|
||||
closesocket(s_discoverySock);
|
||||
s_discoverySock = INVALID_SOCKET;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD timeout = 500;
|
||||
setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
DWORD timeout = 500;
|
||||
setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
|
||||
s_discoveryLegacySock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s_discoveryLegacySock != INVALID_SOCKET)
|
||||
{
|
||||
setsockopt(s_discoveryLegacySock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseAddr, sizeof(reuseAddr));
|
||||
|
||||
bindAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT);
|
||||
if (::bind(s_discoveryLegacySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Legacy discovery bind to port %d failed: %d\n", WIN64_LAN_DISCOVERY_PORT, WSAGetLastError());
|
||||
closesocket(s_discoveryLegacySock);
|
||||
s_discoveryLegacySock = INVALID_SOCKET;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD timeout = 500;
|
||||
setsockopt(s_discoveryLegacySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
if (s_discoverySock == INVALID_SOCKET && s_discoveryLegacySock == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
s_discovering = true;
|
||||
s_discoveryThread = CreateThread(NULL, 0, DiscoveryThreadProc, NULL, 0, NULL);
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Listening for LAN games on UDP port %d\n", WIN64_LAN_DISCOVERY_PORT);
|
||||
app.DebugPrintf("Win64 LAN: Listening for LAN games on UDP ports %d and %d\n", WIN64_NET_DEFAULT_PORT, WIN64_LAN_DISCOVERY_PORT);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -972,6 +1305,12 @@ void WinsockNetLayer::StopDiscovery()
|
|||
s_discoverySock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (s_discoveryLegacySock != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_discoveryLegacySock);
|
||||
s_discoveryLegacySock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (s_discoveryThread != NULL)
|
||||
{
|
||||
WaitForSingleObject(s_discoveryThread, 2000);
|
||||
|
|
@ -1000,98 +1339,127 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
|||
|
||||
while (s_discovering)
|
||||
{
|
||||
struct sockaddr_in senderAddr;
|
||||
int senderLen = sizeof(senderAddr);
|
||||
|
||||
int recvLen = recvfrom(s_discoverySock, recvBuf, sizeof(recvBuf), 0,
|
||||
(struct sockaddr *)&senderAddr, &senderLen);
|
||||
|
||||
if (recvLen == SOCKET_ERROR)
|
||||
fd_set readSet;
|
||||
FD_ZERO(&readSet);
|
||||
int nfds = 0;
|
||||
if (s_discoverySock != INVALID_SOCKET)
|
||||
{
|
||||
continue;
|
||||
FD_SET(s_discoverySock, &readSet);
|
||||
if ((int)s_discoverySock > nfds) nfds = (int)s_discoverySock;
|
||||
}
|
||||
if (s_discoveryLegacySock != INVALID_SOCKET)
|
||||
{
|
||||
FD_SET(s_discoveryLegacySock, &readSet);
|
||||
if ((int)s_discoveryLegacySock > nfds) nfds = (int)s_discoveryLegacySock;
|
||||
}
|
||||
|
||||
if (recvLen < (int)sizeof(Win64LANBroadcast))
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 500000;
|
||||
int selResult = select(nfds + 1, &readSet, NULL, NULL, &tv);
|
||||
if (selResult <= 0)
|
||||
continue;
|
||||
|
||||
Win64LANBroadcast *broadcast = (Win64LANBroadcast *)recvBuf;
|
||||
if (broadcast->magic != WIN64_LAN_BROADCAST_MAGIC)
|
||||
continue;
|
||||
SOCKET readySocks[2];
|
||||
int readyCount = 0;
|
||||
if (s_discoverySock != INVALID_SOCKET && FD_ISSET(s_discoverySock, &readSet))
|
||||
readySocks[readyCount++] = s_discoverySock;
|
||||
if (s_discoveryLegacySock != INVALID_SOCKET && FD_ISSET(s_discoveryLegacySock, &readSet))
|
||||
readySocks[readyCount++] = s_discoveryLegacySock;
|
||||
|
||||
broadcast->hostName[31] = L'\0';
|
||||
|
||||
for (int pn = 0; pn < WIN64_LAN_BROADCAST_PLAYERS; pn++)
|
||||
broadcast->playerNames[pn][XUSER_NAME_SIZE - 1] = '\0';
|
||||
|
||||
char senderIP[64];
|
||||
inet_ntop(AF_INET, &senderAddr.sin_addr, senderIP, sizeof(senderIP));
|
||||
|
||||
DWORD now = GetTickCount();
|
||||
|
||||
EnterCriticalSection(&s_discoveryLock);
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < s_discoveredSessions.size(); i++)
|
||||
for (int si = 0; si < readyCount; si++)
|
||||
{
|
||||
if (strcmp(s_discoveredSessions[i].hostIP, senderIP) == 0 &&
|
||||
s_discoveredSessions[i].hostPort == (int)broadcast->gamePort)
|
||||
{
|
||||
s_discoveredSessions[i].netVersion = broadcast->netVersion;
|
||||
wcsncpy_s(s_discoveredSessions[i].hostName, 32, broadcast->hostName, _TRUNCATE);
|
||||
s_discoveredSessions[i].playerCount = broadcast->playerCount;
|
||||
s_discoveredSessions[i].maxPlayers = broadcast->maxPlayers;
|
||||
s_discoveredSessions[i].gameHostSettings = broadcast->gameHostSettings;
|
||||
s_discoveredSessions[i].texturePackParentId = broadcast->texturePackParentId;
|
||||
s_discoveredSessions[i].subTexturePackId = broadcast->subTexturePackId;
|
||||
s_discoveredSessions[i].isJoinable = (broadcast->isJoinable != 0);
|
||||
s_discoveredSessions[i].isDedicatedServer = (broadcast->isDedicatedServer != 0);
|
||||
s_discoveredSessions[i].lastSeenTick = now;
|
||||
memcpy(s_discoveredSessions[i].playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct sockaddr_in senderAddr;
|
||||
int senderLen = sizeof(senderAddr);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (s_discoveredSessions.size() >= MAX_DISCOVERED_SESSIONS)
|
||||
{
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
int recvLen = recvfrom(readySocks[si], recvBuf, sizeof(recvBuf), 0,
|
||||
(struct sockaddr *)&senderAddr, &senderLen);
|
||||
|
||||
if (recvLen == SOCKET_ERROR)
|
||||
continue;
|
||||
}
|
||||
|
||||
Win64LANSession session;
|
||||
memset(&session, 0, sizeof(session));
|
||||
strncpy_s(session.hostIP, sizeof(session.hostIP), senderIP, _TRUNCATE);
|
||||
session.hostPort = (int)broadcast->gamePort;
|
||||
session.netVersion = broadcast->netVersion;
|
||||
wcsncpy_s(session.hostName, 32, broadcast->hostName, _TRUNCATE);
|
||||
session.playerCount = broadcast->playerCount;
|
||||
session.maxPlayers = broadcast->maxPlayers;
|
||||
session.gameHostSettings = broadcast->gameHostSettings;
|
||||
session.texturePackParentId = broadcast->texturePackParentId;
|
||||
session.subTexturePackId = broadcast->subTexturePackId;
|
||||
session.isJoinable = (broadcast->isJoinable != 0);
|
||||
session.isDedicatedServer = (broadcast->isDedicatedServer != 0);
|
||||
session.lastSeenTick = now;
|
||||
memcpy(session.playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
s_discoveredSessions.push_back(session);
|
||||
if (recvLen < (int)sizeof(Win64LANBroadcast))
|
||||
continue;
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Discovered game \"%ls\" at %s:%d\n",
|
||||
session.hostName, session.hostIP, session.hostPort);
|
||||
}
|
||||
Win64LANBroadcast *broadcast = (Win64LANBroadcast *)recvBuf;
|
||||
if (broadcast->magic != WIN64_LAN_BROADCAST_MAGIC)
|
||||
continue;
|
||||
|
||||
for (size_t i = s_discoveredSessions.size(); i > 0; i--)
|
||||
{
|
||||
if (now - s_discoveredSessions[i - 1].lastSeenTick > 5000)
|
||||
broadcast->hostName[31] = L'\0';
|
||||
|
||||
for (int pn = 0; pn < WIN64_LAN_BROADCAST_PLAYERS; pn++)
|
||||
broadcast->playerNames[pn][XUSER_NAME_SIZE - 1] = '\0';
|
||||
|
||||
char senderIP[64];
|
||||
inet_ntop(AF_INET, &senderAddr.sin_addr, senderIP, sizeof(senderIP));
|
||||
|
||||
DWORD now = GetTickCount();
|
||||
|
||||
EnterCriticalSection(&s_discoveryLock);
|
||||
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < s_discoveredSessions.size(); i++)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Session \"%ls\" at %s timed out\n",
|
||||
s_discoveredSessions[i - 1].hostName, s_discoveredSessions[i - 1].hostIP);
|
||||
s_discoveredSessions.erase(s_discoveredSessions.begin() + (i - 1));
|
||||
if (strcmp(s_discoveredSessions[i].hostIP, senderIP) == 0 &&
|
||||
s_discoveredSessions[i].hostPort == (int)broadcast->gamePort)
|
||||
{
|
||||
s_discoveredSessions[i].netVersion = broadcast->netVersion;
|
||||
wcsncpy_s(s_discoveredSessions[i].hostName, 32, broadcast->hostName, _TRUNCATE);
|
||||
s_discoveredSessions[i].playerCount = broadcast->playerCount;
|
||||
s_discoveredSessions[i].maxPlayers = broadcast->maxPlayers;
|
||||
s_discoveredSessions[i].gameHostSettings = broadcast->gameHostSettings;
|
||||
s_discoveredSessions[i].texturePackParentId = broadcast->texturePackParentId;
|
||||
s_discoveredSessions[i].subTexturePackId = broadcast->subTexturePackId;
|
||||
s_discoveredSessions[i].isJoinable = (broadcast->isJoinable != 0);
|
||||
s_discoveredSessions[i].isDedicatedServer = (broadcast->isDedicatedServer != 0);
|
||||
s_discoveredSessions[i].lastSeenTick = now;
|
||||
memcpy(s_discoveredSessions[i].playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
if (!found)
|
||||
{
|
||||
if (s_discoveredSessions.size() >= MAX_DISCOVERED_SESSIONS)
|
||||
{
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
continue;
|
||||
}
|
||||
|
||||
Win64LANSession session;
|
||||
memset(&session, 0, sizeof(session));
|
||||
strncpy_s(session.hostIP, sizeof(session.hostIP), senderIP, _TRUNCATE);
|
||||
session.hostPort = (int)broadcast->gamePort;
|
||||
session.netVersion = broadcast->netVersion;
|
||||
wcsncpy_s(session.hostName, 32, broadcast->hostName, _TRUNCATE);
|
||||
session.playerCount = broadcast->playerCount;
|
||||
session.maxPlayers = broadcast->maxPlayers;
|
||||
session.gameHostSettings = broadcast->gameHostSettings;
|
||||
session.texturePackParentId = broadcast->texturePackParentId;
|
||||
session.subTexturePackId = broadcast->subTexturePackId;
|
||||
session.isJoinable = (broadcast->isJoinable != 0);
|
||||
session.isDedicatedServer = (broadcast->isDedicatedServer != 0);
|
||||
session.lastSeenTick = now;
|
||||
memcpy(session.playerNames, broadcast->playerNames, sizeof(broadcast->playerNames));
|
||||
s_discoveredSessions.push_back(session);
|
||||
|
||||
app.DebugPrintf("Win64 LAN: Discovered game \"%ls\" at %s:%d\n",
|
||||
session.hostName, session.hostIP, session.hostPort);
|
||||
}
|
||||
|
||||
for (size_t i = s_discoveredSessions.size(); i > 0; i--)
|
||||
{
|
||||
if (now - s_discoveredSessions[i - 1].lastSeenTick > 5000)
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Session \"%ls\" at %s timed out\n",
|
||||
s_discoveredSessions[i - 1].hostName, s_discoveredSessions[i - 1].hostIP);
|
||||
s_discoveredSessions.erase(s_discoveredSessions.begin() + (i - 1));
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&s_discoveryLock);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -14,16 +14,13 @@
|
|||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#define WIN64_NET_DEFAULT_PORT 25565
|
||||
#ifdef _DEDICATED_SERVER
|
||||
#define WIN64_NET_MAX_CLIENTS 31
|
||||
#else
|
||||
#define WIN64_NET_MAX_CLIENTS 7
|
||||
#endif
|
||||
#define WIN64_NET_RECV_BUFFER_SIZE 65536
|
||||
#define WIN64_NET_RECV_BUFFER_SIZE 131072
|
||||
#define WIN64_NET_MAX_PACKET_SIZE (3 * 1024 * 1024)
|
||||
#define WIN64_LAN_DISCOVERY_PORT 25566
|
||||
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
|
||||
#define WIN64_LAN_BROADCAST_PLAYERS 8
|
||||
#define WIN64_NET_SEND_BUFFER_SIZE 262144
|
||||
#define WIN64_NET_MAX_SEND_QUEUE (4 * 1024 * 1024)
|
||||
|
||||
class Socket;
|
||||
|
||||
|
|
@ -66,9 +63,19 @@ struct Win64RemoteConnection
|
|||
{
|
||||
SOCKET tcpSocket;
|
||||
BYTE smallId;
|
||||
HANDLE recvThread;
|
||||
volatile bool active;
|
||||
CRITICAL_SECTION sendLock;
|
||||
|
||||
BYTE *recvBuffer;
|
||||
int recvBufferUsed;
|
||||
int recvBufferSize;
|
||||
int currentPacketSize;
|
||||
bool readingHeader;
|
||||
|
||||
BYTE *sendBuffer;
|
||||
int sendBufferUsed;
|
||||
int sendBufferSize;
|
||||
CRITICAL_SECTION sendBufLock;
|
||||
};
|
||||
|
||||
class WinsockNetLayer
|
||||
|
|
@ -80,6 +87,11 @@ public:
|
|||
static bool HostGame(int port);
|
||||
static bool JoinGame(const char *ip, int port);
|
||||
|
||||
enum JoinResult { JOIN_IN_PROGRESS, JOIN_SUCCESS, JOIN_FAILED };
|
||||
static bool BeginJoinGame(const char *ip, int port);
|
||||
static JoinResult PollJoinResult();
|
||||
static void CancelJoinGame();
|
||||
|
||||
static bool SendToSmallId(BYTE targetSmallId, const void *data, int dataSize);
|
||||
static bool SendOnSocket(SOCKET sock, const void *data, int dataSize);
|
||||
|
||||
|
|
@ -95,6 +107,7 @@ public:
|
|||
|
||||
static void HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize);
|
||||
static void FlushPendingData();
|
||||
static void FlushSendBuffers();
|
||||
|
||||
static bool PopDisconnectedSmallId(BYTE *outSmallId);
|
||||
static void PushFreeSmallId(BYTE smallId);
|
||||
|
|
@ -109,6 +122,7 @@ public:
|
|||
static void UpdateAdvertisePlayerCount(BYTE count);
|
||||
static void UpdateAdvertiseJoinable(bool joinable);
|
||||
static void UpdateAdvertisePlayerNames(BYTE count, const char playerNames[][XUSER_NAME_SIZE]);
|
||||
static void UpdateAdvertiseGameHostSettings(unsigned int settings);
|
||||
|
||||
static bool StartDiscovery();
|
||||
static void StopDiscovery();
|
||||
|
|
@ -117,15 +131,19 @@ public:
|
|||
static int GetHostPort() { return s_hostGamePort; }
|
||||
|
||||
private:
|
||||
static size_t GetConnectionSlotCount();
|
||||
static DWORD WINAPI AcceptThreadProc(LPVOID param);
|
||||
static DWORD WINAPI RecvThreadProc(LPVOID param);
|
||||
static DWORD WINAPI IOThreadProc(LPVOID param);
|
||||
static DWORD WINAPI ClientRecvThreadProc(LPVOID param);
|
||||
static DWORD WINAPI AdvertiseThreadProc(LPVOID param);
|
||||
static DWORD WINAPI DiscoveryThreadProc(LPVOID param);
|
||||
static DWORD WINAPI AsyncJoinThreadProc(LPVOID param);
|
||||
static bool ProcessRecvData(Win64RemoteConnection &conn);
|
||||
|
||||
static SOCKET s_listenSocket;
|
||||
static SOCKET s_hostConnectionSocket;
|
||||
static HANDLE s_acceptThread;
|
||||
static HANDLE s_ioThread;
|
||||
static HANDLE s_clientRecvThread;
|
||||
|
||||
static bool s_isHost;
|
||||
|
|
@ -140,7 +158,7 @@ private:
|
|||
static CRITICAL_SECTION s_sendLock;
|
||||
static CRITICAL_SECTION s_connectionsLock;
|
||||
|
||||
static Win64RemoteConnection s_connections[WIN64_NET_MAX_CLIENTS + 1];
|
||||
static std::vector<Win64RemoteConnection> s_connections;
|
||||
|
||||
static SOCKET s_advertiseSock;
|
||||
static HANDLE s_advertiseThread;
|
||||
|
|
@ -150,6 +168,7 @@ private:
|
|||
static int s_hostGamePort;
|
||||
|
||||
static SOCKET s_discoverySock;
|
||||
static SOCKET s_discoveryLegacySock;
|
||||
static HANDLE s_discoveryThread;
|
||||
static volatile bool s_discovering;
|
||||
static CRITICAL_SECTION s_discoveryLock;
|
||||
|
|
@ -165,7 +184,13 @@ private:
|
|||
static std::vector<BYTE> s_freeSmallIds;
|
||||
|
||||
static CRITICAL_SECTION s_earlyDataLock;
|
||||
static std::vector<BYTE> s_earlyDataBuffers[WIN64_NET_MAX_CLIENTS + 1];
|
||||
static std::vector<std::vector<BYTE> > s_earlyDataBuffers;
|
||||
|
||||
static HANDLE s_asyncJoinThread;
|
||||
static volatile JoinResult s_asyncJoinResult;
|
||||
static volatile bool s_asyncJoinActive;
|
||||
static char s_asyncJoinIP[256];
|
||||
static int s_asyncJoinPort;
|
||||
};
|
||||
|
||||
extern bool g_Win64MultiplayerHost;
|
||||
|
|
|
|||
|
|
@ -40,13 +40,30 @@
|
|||
#include "../../Minecraft.World/OldChunkStorage.h"
|
||||
|
||||
#include "Network/WinsockNetLayer.h"
|
||||
#include "../Common/UI/UIScene_Keyboard.h"
|
||||
|
||||
#include "../PlayerRenderer.h"
|
||||
#include "../LevelRenderer.h"
|
||||
|
||||
#include "Windows64_PostProcess.h"
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
#include "../../Minecraft.Server/Core/ServerThreadPool.h"
|
||||
#endif
|
||||
|
||||
#include "Xbox/resource.h"
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
#include <dxgi1_2.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hMyInst;
|
||||
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
char chGlobalText[256];
|
||||
|
|
@ -88,6 +105,8 @@ int g_iScreenHeight = 1080;
|
|||
char g_Win64Username[17] = {0};
|
||||
wchar_t g_Win64UsernameW[17] = {0};
|
||||
|
||||
static bool g_pendingGracefulWindowClose = false;
|
||||
|
||||
void DefineActions(void)
|
||||
{
|
||||
// The app needs to define the actions required, and the possible mappings for these
|
||||
|
|
@ -351,6 +370,123 @@ ID3D11RenderTargetView* g_pRenderTargetView = NULL;
|
|||
ID3D11DepthStencilView* g_pDepthStencilView = NULL;
|
||||
ID3D11Texture2D* g_pDepthStencilBuffer = NULL;
|
||||
|
||||
static bool g_usesModernSwapChain = false;
|
||||
|
||||
template <typename T>
|
||||
static void SafeRelease(T*& ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->Release();
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT CreateModernDeviceAndSwapChain(UINT createDeviceFlags, const D3D_FEATURE_LEVEL* featureLevels, UINT numFeatureLevels, UINT width, UINT height)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
ID3D11Device* createdDevice = NULL;
|
||||
ID3D11DeviceContext* createdContext = NULL;
|
||||
IDXGISwapChain* createdSwapChain = NULL;
|
||||
|
||||
D3D_DRIVER_TYPE modernDriverTypes[] =
|
||||
{
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
D3D_DRIVER_TYPE_WARP,
|
||||
};
|
||||
|
||||
for (UINT driverTypeIndex = 0; driverTypeIndex < ARRAYSIZE(modernDriverTypes); ++driverTypeIndex)
|
||||
{
|
||||
D3D_FEATURE_LEVEL localFeatureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
hr = D3D11CreateDevice(NULL,
|
||||
modernDriverTypes[driverTypeIndex],
|
||||
NULL,
|
||||
createDeviceFlags,
|
||||
featureLevels,
|
||||
numFeatureLevels,
|
||||
D3D11_SDK_VERSION,
|
||||
&createdDevice,
|
||||
&localFeatureLevel,
|
||||
&createdContext);
|
||||
|
||||
if (HRESULT_SUCCEEDED(hr))
|
||||
{
|
||||
g_driverType = modernDriverTypes[driverTypeIndex];
|
||||
g_featureLevel = localFeatureLevel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
IDXGIDevice* dxgiDevice = NULL;
|
||||
IDXGIDevice1* dxgiDevice1 = NULL;
|
||||
IDXGIAdapter* dxgiAdapter = NULL;
|
||||
IDXGIFactory2* dxgiFactory = NULL;
|
||||
IDXGISwapChain1* swapChain1 = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
hr = createdDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
if (HRESULT_SUCCEEDED(createdDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgiDevice1)))
|
||||
dxgiDevice1->SetMaximumFrameLatency(1);
|
||||
|
||||
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), (void**)&dxgiFactory);
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swapDesc;
|
||||
ZeroMemory(&swapDesc, sizeof(swapDesc));
|
||||
swapDesc.Width = width;
|
||||
swapDesc.Height = height;
|
||||
swapDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapDesc.SampleDesc.Count = 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.BufferCount = 2;
|
||||
swapDesc.Scaling = DXGI_SCALING_STRETCH;
|
||||
#ifdef DXGI_SWAP_EFFECT_FLIP_DISCARD
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
#else
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
#endif
|
||||
swapDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||
swapDesc.Flags = 0;
|
||||
|
||||
hr = dxgiFactory->CreateSwapChainForHwnd(createdDevice, g_hWnd, &swapDesc, NULL, NULL, &swapChain1);
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
dxgiFactory->MakeWindowAssociation(g_hWnd, DXGI_MWA_NO_ALT_ENTER);
|
||||
|
||||
hr = swapChain1->QueryInterface(__uuidof(IDXGISwapChain), (void**)&createdSwapChain);
|
||||
if (FAILED(hr)) break;
|
||||
|
||||
g_pd3dDevice = createdDevice;
|
||||
g_pImmediateContext = createdContext;
|
||||
g_pSwapChain = createdSwapChain;
|
||||
createdDevice = NULL;
|
||||
createdContext = NULL;
|
||||
createdSwapChain = NULL;
|
||||
g_usesModernSwapChain = true;
|
||||
} while (false);
|
||||
|
||||
SafeRelease(swapChain1);
|
||||
SafeRelease(dxgiFactory);
|
||||
SafeRelease(dxgiAdapter);
|
||||
SafeRelease(dxgiDevice1);
|
||||
SafeRelease(dxgiDevice);
|
||||
SafeRelease(createdSwapChain);
|
||||
SafeRelease(createdContext);
|
||||
SafeRelease(createdDevice);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void Windows64_UpdateGamma(unsigned short usGamma)
|
||||
{
|
||||
float gamma = (float)usGamma / 32768.0f;
|
||||
|
|
@ -383,6 +519,49 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
switch (message)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
if (g_pendingGracefulWindowClose)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (app.GetGameStarted())
|
||||
{
|
||||
if (!g_pendingGracefulWindowClose)
|
||||
{
|
||||
int iPad = ProfileManager.GetPrimaryPad();
|
||||
if (iPad < 0 || iPad >= XUSER_MAX_COUNT)
|
||||
{
|
||||
iPad = 0;
|
||||
}
|
||||
|
||||
MinecraftServer *server = MinecraftServer::getInstance();
|
||||
if (server != NULL)
|
||||
{
|
||||
server->setSaveOnExit(true);
|
||||
}
|
||||
|
||||
app.SetAction(iPad, eAppAction_ExitWorld);
|
||||
g_pendingGracefulWindowClose = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (app.GetChangingSessionType() ||
|
||||
app.GetReallyChangingSessionType() ||
|
||||
g_NetworkManager.IsInSession() ||
|
||||
g_NetworkManager.IsLeavingGame() ||
|
||||
g_NetworkManager.IsNetworkThreadRunning() ||
|
||||
StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle)
|
||||
{
|
||||
g_pendingGracefulWindowClose = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
|
||||
case WM_COMMAND:
|
||||
wmId = LOWORD(wParam);
|
||||
wmEvent = HIWORD(wParam);
|
||||
|
|
@ -390,7 +569,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
switch (wmId)
|
||||
{
|
||||
case IDM_EXIT:
|
||||
DestroyWindow(hWnd);
|
||||
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -421,6 +600,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SYSKEYDOWN:
|
||||
{
|
||||
int vk = (int)wParam;
|
||||
if (vk == VK_F12)
|
||||
return 0;
|
||||
if (Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
if (vk == VK_LEFT || vk == VK_RIGHT || vk == VK_ESCAPE)
|
||||
{
|
||||
Win64InGameKeyboard::OnVirtualKeyDown((unsigned int)vk);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (vk == VK_F11)
|
||||
{
|
||||
ToggleFullscreen();
|
||||
|
|
@ -440,6 +629,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SYSKEYUP:
|
||||
{
|
||||
int vk = (int)wParam;
|
||||
if (vk == VK_F12)
|
||||
return 0;
|
||||
if (vk == VK_SHIFT)
|
||||
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
||||
else if (vk == VK_CONTROL)
|
||||
|
|
@ -450,6 +641,28 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
}
|
||||
|
||||
case WM_CHAR:
|
||||
case WM_SYSCHAR:
|
||||
case WM_IME_CHAR:
|
||||
if (Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
Win64InGameKeyboard::OnChar((wchar_t)wParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_UNICHAR:
|
||||
if (wParam == UNICODE_NOCHAR)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (Win64InGameKeyboard::IsActive())
|
||||
{
|
||||
Win64InGameKeyboard::OnChar((wchar_t)wParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
|
||||
break;
|
||||
|
|
@ -659,7 +872,7 @@ HRESULT InitDevice()
|
|||
height = g_iScreenHeight;
|
||||
app.DebugPrintf("width: %d, height: %d\n", width, height);
|
||||
|
||||
UINT createDeviceFlags = 0;
|
||||
UINT createDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
#ifdef _DEBUG
|
||||
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
|
@ -680,31 +893,40 @@ app.DebugPrintf("width: %d, height: %d\n", width, height);
|
|||
};
|
||||
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory( &sd, sizeof( sd ) );
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = width;
|
||||
sd.BufferDesc.Height = height;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = g_hWnd;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
g_usesModernSwapChain = false;
|
||||
hr = CreateModernDeviceAndSwapChain(createDeviceFlags, featureLevels, numFeatureLevels, width, height);
|
||||
|
||||
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
|
||||
if (FAILED(hr))
|
||||
{
|
||||
g_driverType = driverTypes[driverTypeIndex];
|
||||
hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
|
||||
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
|
||||
if( HRESULT_SUCCEEDED( hr ) )
|
||||
break;
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory( &sd, sizeof( sd ) );
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = width;
|
||||
sd.BufferDesc.Height = height;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = g_hWnd;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
|
||||
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
|
||||
{
|
||||
g_driverType = driverTypes[driverTypeIndex];
|
||||
hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
|
||||
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
|
||||
if( HRESULT_SUCCEEDED( hr ) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( FAILED( hr ) )
|
||||
return hr;
|
||||
|
||||
app.DebugPrintf("Renderer init: %s swap chain\n", g_usesModernSwapChain ? "DXGI flip-model" : "legacy");
|
||||
|
||||
// Create a render target view
|
||||
ID3D11Texture2D* pBackBuffer = NULL;
|
||||
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
|
||||
|
|
@ -890,6 +1112,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
#if 0
|
||||
// Main message loop
|
||||
MSG msg = {0};
|
||||
DWORD menuFrameStart = 0;
|
||||
while( WM_QUIT != msg.message )
|
||||
{
|
||||
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
|
||||
|
|
@ -1109,6 +1332,16 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
|
||||
app.InitGameSettings();
|
||||
|
||||
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
|
||||
{
|
||||
void *pData = ProfileManager.GetGameDefinedProfileData(i);
|
||||
if (pData != NULL && pMinecraft->stats[i] != NULL)
|
||||
{
|
||||
pMinecraft->stats[i]->clear();
|
||||
pMinecraft->stats[i]->parse(pData);
|
||||
}
|
||||
}
|
||||
|
||||
if(app.GetGameSettings(eGameSetting_Fullscreen) != 0)
|
||||
{
|
||||
if(!g_isFullscreen)
|
||||
|
|
@ -1204,6 +1437,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
}
|
||||
#endif
|
||||
MSG msg = {0};
|
||||
DWORD menuFrameStart = 0;
|
||||
while( WM_QUIT != msg.message )
|
||||
{
|
||||
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
|
||||
|
|
@ -1214,6 +1448,22 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
}
|
||||
if (msg.message == WM_QUIT) break;
|
||||
|
||||
if (!app.GetGameStarted() || pMinecraft->screen != NULL)
|
||||
{
|
||||
const DWORD now = GetTickCount();
|
||||
if (menuFrameStart != 0)
|
||||
{
|
||||
const DWORD elapsed = now - menuFrameStart;
|
||||
if (elapsed < 16)
|
||||
Sleep(16 - elapsed);
|
||||
}
|
||||
menuFrameStart = GetTickCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
menuFrameStart = 0;
|
||||
}
|
||||
|
||||
g_KBMInput.Tick();
|
||||
|
||||
RenderManager.StartFrame();
|
||||
|
|
@ -1454,6 +1704,22 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
// Any threading type things to deal with from the xui side?
|
||||
app.HandleXuiActions();
|
||||
|
||||
if (g_pendingGracefulWindowClose)
|
||||
{
|
||||
if (!app.GetGameStarted() &&
|
||||
!app.GetChangingSessionType() &&
|
||||
!app.GetReallyChangingSessionType() &&
|
||||
!g_NetworkManager.IsInSession() &&
|
||||
!g_NetworkManager.IsLeavingGame() &&
|
||||
!g_NetworkManager.IsNetworkThreadRunning() &&
|
||||
StorageManager.GetSaveState() == C4JStorage::ESaveGame_Idle)
|
||||
{
|
||||
g_pendingGracefulWindowClose = false;
|
||||
DestroyWindow(g_hWnd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
PIXEndNamedEvent();
|
||||
#endif
|
||||
|
|
@ -1489,7 +1755,15 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
|
||||
// Free resources, unregister custom classes, and exit.
|
||||
// app.Uninit();
|
||||
g_pd3dDevice->Release();
|
||||
#ifdef _LARGE_WORLDS
|
||||
LevelRenderer::shutdownRebuildThreads();
|
||||
#endif
|
||||
g_NetworkManager.Terminate();
|
||||
#if defined(__linux__) || defined(_WIN32)
|
||||
ServerThreadPool::Shutdown();
|
||||
#endif
|
||||
CleanupDevice();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_TRACKING
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "Windows64_PostProcess.h"
|
||||
#include <d3dcompiler.h>
|
||||
#pragma comment(lib, "d3dcompiler.lib")
|
||||
#include "GammaPostProcessVS.h"
|
||||
#include "GammaPostProcessPS.h"
|
||||
|
||||
extern ID3D11Device* g_pd3dDevice;
|
||||
extern ID3D11DeviceContext* g_pImmediateContext;
|
||||
|
|
@ -27,28 +27,6 @@ struct GammaCBData
|
|||
float pad[3];
|
||||
};
|
||||
|
||||
static const char* g_gammaVSCode =
|
||||
"void main(uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" uv = float2((id << 1) & 2, id & 2);\n"
|
||||
" pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* g_gammaPSCode =
|
||||
"cbuffer GammaCB : register(b0)\n"
|
||||
"{\n"
|
||||
" float gamma;\n"
|
||||
" float3 pad;\n"
|
||||
"};\n"
|
||||
"Texture2D sceneTex : register(t0);\n"
|
||||
"SamplerState sceneSampler : register(s0);\n"
|
||||
"float4 main(float4 pos : SV_Position, float2 uv : TEXCOORD0) : SV_Target\n"
|
||||
"{\n"
|
||||
" float4 color = sceneTex.Sample(sceneSampler, uv);\n"
|
||||
" color.rgb = pow(max(color.rgb, 0.0), 1.0 / gamma);\n"
|
||||
" return color;\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
void SetGammaValue(float gamma)
|
||||
{
|
||||
|
|
@ -89,30 +67,10 @@ bool InitGammaPostProcess()
|
|||
hr = g_pd3dDevice->CreateRenderTargetView(g_pGammaOffscreenTex, NULL, &g_pGammaOffscreenRTV);
|
||||
if (FAILED(hr)) return false;
|
||||
|
||||
ID3DBlob* vsBlob = NULL;
|
||||
ID3DBlob* errBlob = NULL;
|
||||
hr = D3DCompile(g_gammaVSCode, strlen(g_gammaVSCode), "GammaVS", NULL, NULL, "main", "vs_4_0", 0, 0, &vsBlob, &errBlob);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (errBlob) errBlob->Release();
|
||||
return false;
|
||||
}
|
||||
hr = g_pd3dDevice->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, &g_pGammaVS);
|
||||
vsBlob->Release();
|
||||
if (errBlob) errBlob->Release();
|
||||
hr = g_pd3dDevice->CreateVertexShader(g_gammaPostProcessVS, sizeof(g_gammaPostProcessVS), NULL, &g_pGammaVS);
|
||||
if (FAILED(hr)) return false;
|
||||
|
||||
errBlob = NULL;
|
||||
ID3DBlob* psBlob = NULL;
|
||||
hr = D3DCompile(g_gammaPSCode, strlen(g_gammaPSCode), "GammaPS", NULL, NULL, "main", "ps_4_0", 0, 0, &psBlob, &errBlob);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (errBlob) errBlob->Release();
|
||||
return false;
|
||||
}
|
||||
hr = g_pd3dDevice->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, &g_pGammaPS);
|
||||
psBlob->Release();
|
||||
if (errBlob) errBlob->Release();
|
||||
hr = g_pd3dDevice->CreatePixelShader(g_gammaPostProcessPS, sizeof(g_gammaPostProcessPS), NULL, &g_pGammaPS);
|
||||
if (FAILED(hr)) return false;
|
||||
|
||||
D3D11_BUFFER_DESC cbDesc;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@
|
|||
|
||||
#define __STR2__(x) #x
|
||||
#define __STR1__(x) __STR2__(x)
|
||||
#define __LOC__ __FILE__ "("__STR1__(__LINE__)") : 4J Warning Msg: "
|
||||
#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : 4J Warning Msg: "
|
||||
|
||||
#ifndef UNREFERENCED_PARAMETER
|
||||
#define UNREFERENCED_PARAMETER(P) (void)(P)
|
||||
#endif
|
||||
|
||||
// use - #pragma message(__LOC__"Need to do something here")
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f3fc8574c821bf2f785fa49955a0b16dddbeb995
|
||||
Subproject commit 797530e883fb12887dbc40ff7e0f39b16771b9bc
|
||||
|
|
@ -29,6 +29,7 @@ void Connection::_init()
|
|||
running = true;
|
||||
quitting = false;
|
||||
disconnected = false;
|
||||
m_closeState = 0;
|
||||
disconnectReason = DisconnectPacket::eDisconnect_None;
|
||||
noInputTicks = 0;
|
||||
estimatedRemaining = 0;
|
||||
|
|
@ -45,12 +46,19 @@ void Connection::_init()
|
|||
// 4J Jev, need to delete the critical section.
|
||||
Connection::~Connection()
|
||||
{
|
||||
// 4J Stu - Just to be sure, make sure the read and write threads terminate themselves before the connection object is destroyed
|
||||
running = false;
|
||||
if( dis ) dis->close(); // The input stream needs closed before the readThread, or the readThread
|
||||
// may get stuck whilst blocking waiting on a read
|
||||
readThread->WaitForCompletion(INFINITE);
|
||||
writeThread->WaitForCompletion(INFINITE);
|
||||
LONG closeState = InterlockedCompareExchange(&m_closeState, 1, 0);
|
||||
if (closeState == 0)
|
||||
{
|
||||
shutdownConnectionResources();
|
||||
InterlockedExchange(&m_closeState, 2);
|
||||
}
|
||||
else if (closeState == 1)
|
||||
{
|
||||
while (InterlockedCompareExchange(&m_closeState, 2, 2) != 2)
|
||||
{
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&writeLock);
|
||||
DeleteCriticalSection(&threadCounterLock);
|
||||
|
|
@ -74,6 +82,36 @@ Connection::~Connection()
|
|||
dis = NULL;
|
||||
}
|
||||
|
||||
void Connection::shutdownConnectionResources()
|
||||
{
|
||||
running = false;
|
||||
if( dis ) dis->close();
|
||||
|
||||
if( readThread ) readThread->WaitForCompletion(INFINITE);
|
||||
if( writeThread ) writeThread->WaitForCompletion(INFINITE);
|
||||
|
||||
delete dis;
|
||||
dis = NULL;
|
||||
if( bufferedDos )
|
||||
{
|
||||
bufferedDos->close();
|
||||
bufferedDos->deleteChildStream();
|
||||
delete bufferedDos;
|
||||
bufferedDos = NULL;
|
||||
}
|
||||
if( byteArrayDos )
|
||||
{
|
||||
byteArrayDos->close();
|
||||
delete byteArrayDos;
|
||||
byteArrayDos = NULL;
|
||||
}
|
||||
if( socket )
|
||||
{
|
||||
socket->close(packetListener != NULL ? packetListener->isServerPacketListener() : false);
|
||||
socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Connection::Connection(Socket *socket, const wstring& id, PacketListener *packetListener) // throws IOException
|
||||
{
|
||||
_init();
|
||||
|
|
@ -334,31 +372,16 @@ close("disconnect.genericReason", "Internal exception: " + e.toString());
|
|||
void Connection::close(DisconnectPacket::eDisconnectReason reason, ...)
|
||||
{
|
||||
// printf("Con:0x%x close\n",this);
|
||||
if (!running) return;
|
||||
if (InterlockedCompareExchange(&m_closeState, 1, 0) != 0) return;
|
||||
// printf("Con:0x%x close doing something\n",this);
|
||||
disconnected = true;
|
||||
|
||||
va_list input;
|
||||
va_start( input, reason );
|
||||
|
||||
disconnectReason = reason;//va_arg( input, const wstring );
|
||||
|
||||
vector<void *> objs = vector<void *>();
|
||||
void *i = NULL;
|
||||
while (i != NULL)
|
||||
{
|
||||
i = va_arg( input, void* );
|
||||
objs.push_back(i);
|
||||
}
|
||||
|
||||
if( objs.size() )
|
||||
{
|
||||
disconnectReasonObjects = &objs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnectReasonObjects = NULL;
|
||||
}
|
||||
disconnectReason = reason;
|
||||
disconnectReasonObjects = NULL;
|
||||
va_end(input);
|
||||
|
||||
// int count = 0, sum = 0, i = first;
|
||||
// va_list marker;
|
||||
|
|
@ -376,35 +399,8 @@ void Connection::close(DisconnectPacket::eDisconnectReason reason, ...)
|
|||
|
||||
// CreateThread(NULL, 0, runClose, this, 0, &closeThreadID);
|
||||
|
||||
running = false;
|
||||
|
||||
if( dis ) dis->close(); // The input stream needs closed before the readThread, or the readThread
|
||||
// may get stuck whilst blocking waiting on a read
|
||||
|
||||
// Make sure that the read & write threads are dead before we go and kill the streams that they depend on
|
||||
readThread->WaitForCompletion(INFINITE);
|
||||
writeThread->WaitForCompletion(INFINITE);
|
||||
|
||||
delete dis;
|
||||
dis = NULL;
|
||||
if( bufferedDos )
|
||||
{
|
||||
bufferedDos->close();
|
||||
bufferedDos->deleteChildStream();
|
||||
delete bufferedDos;
|
||||
bufferedDos = NULL;
|
||||
}
|
||||
if( byteArrayDos )
|
||||
{
|
||||
byteArrayDos->close();
|
||||
delete byteArrayDos;
|
||||
byteArrayDos = NULL;
|
||||
}
|
||||
if( socket )
|
||||
{
|
||||
socket->close(packetListener->isServerPacketListener());
|
||||
socket = NULL;
|
||||
}
|
||||
shutdownConnectionResources();
|
||||
InterlockedExchange(&m_closeState, 2);
|
||||
}
|
||||
|
||||
void Connection::tick()
|
||||
|
|
@ -467,6 +463,12 @@ void Connection::tick()
|
|||
// MGH - moved the packet handling outside of the incoming_cs block, as it was locking up sometimes when disconnecting
|
||||
for(int i=0; i<packetsToHandle.size();i++)
|
||||
{
|
||||
// if a packet handler disconnected this connection, drop any remaining queued packets
|
||||
if (disconnected || quitting || packetListener == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
PIXBeginNamedEvent(0,"Handling packet %d\n",packetsToHandle[i]->getId());
|
||||
packetsToHandle[i]->handle(packetListener);
|
||||
PIXEndNamedEvent();
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ private:
|
|||
DataOutputStream *byteArrayDos; // 4J This dos allows us to write individual packets to the socket
|
||||
ByteArrayOutputStream *baos;
|
||||
Socket::SocketOutputStream *sos;
|
||||
volatile LONG m_closeState;
|
||||
|
||||
bool running;
|
||||
|
||||
|
|
@ -87,6 +88,7 @@ public:
|
|||
|
||||
private:
|
||||
void _init();
|
||||
void shutdownConnectionResources();
|
||||
|
||||
// 4J Jev, these might be better of as private
|
||||
CRITICAL_SECTION threadCounterLock;
|
||||
|
|
|
|||
|
|
@ -810,7 +810,8 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail )
|
|||
|
||||
int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes)
|
||||
{
|
||||
ConsoleSaveFile *pClass=(ConsoleSaveFile *)lpParam;
|
||||
(void)lpParam;
|
||||
(void)bRes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,9 +143,6 @@ void Inventory::grabTexture(int id, int data, bool checkData, bool mayReplace)
|
|||
|
||||
void Inventory::swapPaint(int wheel)
|
||||
{
|
||||
if (wheel > 0) wheel = 1;
|
||||
if (wheel < 0) wheel = -1;
|
||||
|
||||
selected -= wheel;
|
||||
|
||||
while (selected < 0)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ C4JThread *McRegionChunkStorage::s_saveThreads[3];
|
|||
McRegionChunkStorage::McRegionChunkStorage(ConsoleSaveFile *saveFile, const wstring &prefix) : m_prefix( prefix )
|
||||
{
|
||||
m_saveFile = saveFile;
|
||||
InitializeCriticalSectionAndSpinCount(&m_csEntityData, 4000);
|
||||
|
||||
// Make sure that if there are any files for regions to be created, that they are created in the order that suits us for making the initial level save work fast
|
||||
if( prefix == L"" )
|
||||
|
|
@ -68,6 +69,7 @@ McRegionChunkStorage::~McRegionChunkStorage()
|
|||
{
|
||||
delete it->second.data;
|
||||
}
|
||||
DeleteCriticalSection(&m_csEntityData);
|
||||
}
|
||||
|
||||
LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z)
|
||||
|
|
@ -75,17 +77,18 @@ LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z)
|
|||
DataInputStream *regionChunkInputStream = RegionFileCache::getChunkDataInputStream(m_saveFile, m_prefix, x, z);
|
||||
|
||||
#ifdef SPLIT_SAVES
|
||||
// If we can't find the chunk in the save file, then we should remove any entities we might have for that chunk
|
||||
if(regionChunkInputStream == NULL)
|
||||
{
|
||||
__int64 index = ((__int64)(x) << 32) | (((__int64)(z))&0x00000000FFFFFFFF);
|
||||
|
||||
EnterCriticalSection(&m_csEntityData);
|
||||
AUTO_VAR(it, m_entityData.find(index));
|
||||
if(it != m_entityData.end())
|
||||
{
|
||||
delete it->second.data;
|
||||
m_entityData.erase(it);
|
||||
}
|
||||
LeaveCriticalSection(&m_csEntityData);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -237,11 +240,12 @@ void McRegionChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk)
|
|||
PIXBeginNamedEvent(0,"Saving entities");
|
||||
__int64 index = ((__int64)(levelChunk->x) << 32) | (((__int64)(levelChunk->z))&0x00000000FFFFFFFF);
|
||||
|
||||
delete m_entityData[index].data;
|
||||
|
||||
CompoundTag *newTag = new CompoundTag();
|
||||
bool savedEntities = OldChunkStorage::saveEntities(levelChunk, level, newTag);
|
||||
|
||||
EnterCriticalSection(&m_csEntityData);
|
||||
delete m_entityData[index].data;
|
||||
|
||||
if(savedEntities)
|
||||
{
|
||||
ByteArrayOutputStream bos;
|
||||
|
|
@ -261,6 +265,7 @@ void McRegionChunkStorage::saveEntities(Level *level, LevelChunk *levelChunk)
|
|||
m_entityData.erase(it);
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&m_csEntityData);
|
||||
delete newTag;
|
||||
PIXEndNamedEvent();
|
||||
#endif
|
||||
|
|
@ -271,16 +276,22 @@ void McRegionChunkStorage::loadEntities(Level *level, LevelChunk *levelChunk)
|
|||
#ifdef SPLIT_SAVES
|
||||
__int64 index = ((__int64)(levelChunk->x) << 32) | (((__int64)(levelChunk->z))&0x00000000FFFFFFFF);
|
||||
|
||||
EnterCriticalSection(&m_csEntityData);
|
||||
AUTO_VAR(it, m_entityData.find(index));
|
||||
if(it != m_entityData.end())
|
||||
{
|
||||
ByteArrayInputStream bais(it->second);
|
||||
DataInputStream dis(&bais);
|
||||
CompoundTag *tag = NbtIo::read(&dis);
|
||||
LeaveCriticalSection(&m_csEntityData);
|
||||
OldChunkStorage::loadEntities(levelChunk, level, tag);
|
||||
bais.reset();
|
||||
delete tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
LeaveCriticalSection(&m_csEntityData);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +310,7 @@ void McRegionChunkStorage::flush()
|
|||
DataOutputStream dos(&bos);
|
||||
|
||||
PIXBeginNamedEvent(0,"Writing to stream");
|
||||
EnterCriticalSection(&m_csEntityData);
|
||||
dos.writeInt(m_entityData.size());
|
||||
|
||||
for(AUTO_VAR(it,m_entityData.begin()); it != m_entityData.end(); ++it)
|
||||
|
|
@ -306,6 +318,7 @@ void McRegionChunkStorage::flush()
|
|||
dos.writeLong(it->first);
|
||||
dos.write(it->second,0,it->second.length);
|
||||
}
|
||||
LeaveCriticalSection(&m_csEntityData);
|
||||
bos.flush();
|
||||
PIXEndNamedEvent();
|
||||
PIXEndNamedEvent();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ private:
|
|||
static CRITICAL_SECTION cs_memory;
|
||||
|
||||
unordered_map<__int64, byteArray> m_entityData;
|
||||
CRITICAL_SECTION m_csEntityData;
|
||||
|
||||
static std::deque<DataOutputStream *> s_chunkDataQueue;
|
||||
static int s_runningThreadCount;
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@
|
|||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<ApplicationEnvironment>title</ApplicationEnvironment>
|
||||
<WindowsTargetPlatformVersion Condition="'$(Platform)'=='x64'">10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'" Label="Configuration">
|
||||
|
|
@ -3957,7 +3958,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="ZoomLayer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(Platform)'=='Durango'">
|
||||
<SDKReference Include="Xbox Services API, Version=8.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
|||
|
|
@ -32,12 +32,7 @@ TilePos MobSpawner::getRandomPosWithin(Level *level, int cx, int cz)
|
|||
return TilePos(x, y, z);
|
||||
}
|
||||
|
||||
#ifdef __PSVITA__
|
||||
// AP - See CustomMap.h for an explanation of this
|
||||
CustomMap MobSpawner::chunksToPoll;
|
||||
#else
|
||||
unordered_map<ChunkPos,bool,ChunkPosKeyHash,ChunkPosKeyEq> MobSpawner::chunksToPoll;
|
||||
#endif
|
||||
|
||||
|
||||
const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies)
|
||||
{
|
||||
|
|
@ -99,7 +94,11 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
|
|||
return 0;
|
||||
}
|
||||
MemSect(20);
|
||||
chunksToPoll.clear();
|
||||
#ifdef __PSVITA__
|
||||
CustomMap chunksToPoll;
|
||||
#else
|
||||
unordered_map<ChunkPos,bool,ChunkPosKeyHash,ChunkPosKeyEq> chunksToPoll;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
AUTO_VAR(itEnd, level->players.end());
|
||||
|
|
|
|||
|
|
@ -17,14 +17,6 @@ private:
|
|||
protected:
|
||||
static TilePos getRandomPosWithin(Level *level, int cx, int cz);
|
||||
|
||||
private:
|
||||
#ifdef __PSVITA__
|
||||
// AP - See CustomMap.h for an explanation of this
|
||||
static CustomMap chunksToPoll;
|
||||
#else
|
||||
static unordered_map<ChunkPos,bool,ChunkPosKeyHash,ChunkPosKeyEq> chunksToPoll;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static const int tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies);
|
||||
static bool isSpawnPositionOk(MobCategory *category, Level *level, int x, int y, int z);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ byteArray RegionFile::emptySector(SECTOR_BYTES);
|
|||
|
||||
RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path)
|
||||
{
|
||||
InitializeCriticalSectionAndSpinCount(&m_cs, 4000);
|
||||
_lastModified = 0;
|
||||
|
||||
m_saveFile = saveFile;
|
||||
|
|
@ -136,11 +137,11 @@ RegionFile::RegionFile(ConsoleSaveFile *saveFile, File *path)
|
|||
// }
|
||||
}
|
||||
|
||||
void RegionFile::writeAllOffsets() // used for the file ConsoleSaveFile conversion between platforms
|
||||
void RegionFile::writeAllOffsets()
|
||||
{
|
||||
if(m_bIsEmpty == false)
|
||||
{
|
||||
// save all the offsets and timestamps
|
||||
EnterCriticalSection(&m_cs);
|
||||
m_saveFile->LockSaveAccess();
|
||||
|
||||
DWORD numberOfBytesWritten = 0;
|
||||
|
|
@ -152,6 +153,7 @@ void RegionFile::writeAllOffsets() // used for the file ConsoleSaveFile conversi
|
|||
m_saveFile->writeFile(fileEntry, chunkTimestamps, SECTOR_BYTES, &numberOfBytesWritten);
|
||||
|
||||
m_saveFile->ReleaseSaveAccess();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -161,6 +163,7 @@ RegionFile::~RegionFile()
|
|||
delete[] chunkTimestamps;
|
||||
delete sectorFree;
|
||||
m_saveFile->closeHandle( fileEntry );
|
||||
DeleteCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
__int64 RegionFile::lastModified()
|
||||
|
|
@ -168,27 +171,28 @@ __int64 RegionFile::lastModified()
|
|||
return _lastModified;
|
||||
}
|
||||
|
||||
int RegionFile::getSizeDelta() // TODO - was synchronized
|
||||
int RegionFile::getSizeDelta()
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
int ret = sizeDelta;
|
||||
sizeDelta = 0;
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was synchronized
|
||||
DataInputStream *RegionFile::getChunkDataInputStream(int x, int z)
|
||||
{
|
||||
if (outOfBounds(x, z))
|
||||
{
|
||||
// debugln("READ", x, z, "out of bounds");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 4J - removed try/catch
|
||||
// try {
|
||||
EnterCriticalSection(&m_cs);
|
||||
|
||||
int offset = getOffset(x, z);
|
||||
if (offset == 0)
|
||||
{
|
||||
// debugln("READ", x, z, "miss");
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -197,13 +201,12 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was
|
|||
|
||||
if (sectorNumber + numSectors > sectorFree->size())
|
||||
{
|
||||
// debugln("READ", x, z, "invalid sector");
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_saveFile->LockSaveAccess();
|
||||
|
||||
//SetFilePointer(file,sectorNumber * SECTOR_BYTES,0,FILE_BEGIN);
|
||||
m_saveFile->setFilePointer( fileEntry, sectorNumber * SECTOR_BYTES, NULL, FILE_BEGIN);
|
||||
|
||||
unsigned int length;
|
||||
|
|
@ -212,13 +215,10 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was
|
|||
|
||||
DWORD numberOfBytesRead = 0;
|
||||
|
||||
// 4J - this differs a bit from the java file format. Java has length stored as an int, then a type as a byte, then length-1 bytes of data
|
||||
// We store length and decompression length as ints, then length bytes of xbox LZX compressed data
|
||||
m_saveFile->readFile(fileEntry,&length,4,&numberOfBytesRead);
|
||||
|
||||
if(m_saveFile->isSaveEndianDifferent()) System::ReverseULONG(&length);
|
||||
|
||||
// Using to bit of length to signify that this data was compressed with RLE method
|
||||
bool useRLE = false;
|
||||
if( length & 0x80000000 )
|
||||
{
|
||||
|
|
@ -231,9 +231,8 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was
|
|||
|
||||
if (length > SECTOR_BYTES * numSectors)
|
||||
{
|
||||
// debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors);
|
||||
|
||||
m_saveFile->ReleaseSaveAccess();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -245,8 +244,9 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was
|
|||
m_saveFile->readFile(fileEntry,data,length,&numberOfBytesRead);
|
||||
|
||||
m_saveFile->ReleaseSaveAccess();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
|
||||
Compression::getCompression()->SetDecompressionType(m_saveFile->getSavePlatform()); // if this save is from another platform, set the correct decompression type
|
||||
Compression::getCompression()->SetDecompressionType(m_saveFile->getSavePlatform());
|
||||
|
||||
if( useRLE )
|
||||
{
|
||||
|
|
@ -257,18 +257,12 @@ DataInputStream *RegionFile::getChunkDataInputStream(int x, int z) // TODO - was
|
|||
Compression::getCompression()->Decompress(decomp, &readDecompLength, data, length );
|
||||
}
|
||||
|
||||
Compression::getCompression()->SetDecompressionType(SAVE_FILE_PLATFORM_LOCAL); // and then set the decompression back to the local machine's standard type
|
||||
Compression::getCompression()->SetDecompressionType(SAVE_FILE_PLATFORM_LOCAL);
|
||||
|
||||
delete [] data;
|
||||
|
||||
// 4J - was InflaterInputStream in here too, but we've already decompressed
|
||||
DataInputStream *ret = new DataInputStream(new ByteArrayInputStream( byteArray( decomp, readDecompLength) ));
|
||||
return ret;
|
||||
|
||||
// } catch (IOException e) {
|
||||
// debugln("READ", x, z, "exception");
|
||||
// return null;
|
||||
// }
|
||||
}
|
||||
|
||||
DataOutputStream *RegionFile::getChunkDataOutputStream(int x, int z)
|
||||
|
|
@ -278,23 +272,20 @@ DataOutputStream *RegionFile::getChunkDataOutputStream(int x, int z)
|
|||
}
|
||||
|
||||
/* write a chunk at (x,z) with length bytes of data to disk */
|
||||
void RegionFile::write(int x, int z, byte *data, int length) // TODO - was synchronized
|
||||
void RegionFile::write(int x, int z, byte *data, int length)
|
||||
{
|
||||
// 4J Stu - Do the compression here so that we know how much space we need to store the compressed data
|
||||
byte *compData = new byte[length + 2048]; // presuming compression is going to make this smaller... UPDATE - for some really small things this isn't the case. Added 2K on here to cover those.
|
||||
byte *compData = new byte[length + 2048];
|
||||
unsigned int compLength = length;
|
||||
Compression::getCompression()->CompressLZXRLE(compData,&compLength,data,length);
|
||||
|
||||
int sectorsNeeded = (compLength + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1;
|
||||
|
||||
// app.DebugPrintf(">>>>>>>>>>>>>> writing compressed data for 0x%.8x, %d %d\n",fileEntry->data.regionIndex,x,z);
|
||||
|
||||
// maximum chunk size is 1MB
|
||||
if (sectorsNeeded >= 256)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&m_cs);
|
||||
m_saveFile->LockSaveAccess();
|
||||
{
|
||||
int offset = getOffset(x, z);
|
||||
|
|
@ -401,10 +392,7 @@ void RegionFile::write(int x, int z, byte *data, int length) // TODO - was sync
|
|||
setTimestamp(x, z, (int) (System::currentTimeMillis() / 1000L));
|
||||
}
|
||||
m_saveFile->ReleaseSaveAccess();
|
||||
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
LeaveCriticalSection(&m_cs);
|
||||
}
|
||||
|
||||
/* write a chunk data to the region file at specified sector number */
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ private:
|
|||
int sizeDelta;
|
||||
__int64 _lastModified;
|
||||
bool m_bIsEmpty; // 4J added
|
||||
CRITICAL_SECTION m_cs;
|
||||
|
||||
public:
|
||||
RegionFile(ConsoleSaveFile *saveFile, File *path);
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@ bool RegionFileCache::useSplitSaves(ESavePlatform platform)
|
|||
};
|
||||
}
|
||||
|
||||
RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ) // 4J - synchronized restored
|
||||
RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ)
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
|
||||
// 4J Jev - changed back to use of the File class.
|
||||
MemSect(31);
|
||||
File file;
|
||||
|
|
@ -34,28 +32,29 @@ RegionFile *RegionFileCache::_getRegionFile(ConsoleSaveFile *saveFile, const wst
|
|||
}
|
||||
MemSect(0);
|
||||
|
||||
EnterCriticalSection(&m_cs);
|
||||
|
||||
RegionFile *ref = NULL;
|
||||
AUTO_VAR(it, cache.find(file));
|
||||
if( it != cache.end() )
|
||||
ref = it->second;
|
||||
|
||||
// 4J Jev, put back in.
|
||||
if (ref != NULL)
|
||||
if (ref != NULL)
|
||||
{
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.size() >= MAX_CACHE_SIZE)
|
||||
if (cache.size() >= MAX_CACHE_SIZE)
|
||||
{
|
||||
_clear();
|
||||
}
|
||||
_clear();
|
||||
}
|
||||
|
||||
RegionFile *reg = new RegionFile(saveFile, &file);
|
||||
cache[file] = reg; // 4J - this was originally a softReference
|
||||
cache[file] = reg; // 4J - this was originally a softReference
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return reg;
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
void RegionFileCache::_clear() // 4J - synchronized (recursive CS is safe here)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const int MINECRAFT_NET_MAX_PLAYERS = 4;
|
|||
const int XUSER_MAX_COUNT = 4;
|
||||
#endif
|
||||
#if defined(_DEDICATED_SERVER) || defined(_WINDOWS64)
|
||||
const int MINECRAFT_NET_MAX_PLAYERS = 32;
|
||||
const int MINECRAFT_NET_MAX_PLAYERS = 255;
|
||||
#else
|
||||
const int MINECRAFT_NET_MAX_PLAYERS = 8;
|
||||
#endif
|
||||
|
|
@ -332,8 +332,11 @@ public:
|
|||
void HostGame();
|
||||
void ClientJoinGame();
|
||||
void EndGame();
|
||||
static void SetPlayerCapacity(DWORD capacity);
|
||||
static DWORD GetPlayerCapacity();
|
||||
|
||||
static IQNetPlayer m_player[MINECRAFT_NET_MAX_PLAYERS];
|
||||
static IQNetPlayer *m_player;
|
||||
static DWORD s_playerCapacity;
|
||||
static DWORD s_playerCount;
|
||||
static bool s_isHosting;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ set(MINECRAFT_SERVER_OWN_SOURCES
|
|||
"Core/ServerLogger.cpp"
|
||||
"Core/ServerLists.cpp"
|
||||
"Core/ServerProperties.cpp"
|
||||
"Core/ServerThreadPool.cpp"
|
||||
"Stubs/ServerStubs.cpp"
|
||||
"Stubs/ServerStubs2.cpp"
|
||||
"Stubs/ServerStubs3.cpp"
|
||||
|
|
|
|||
|
|
@ -443,6 +443,7 @@ set(MINECRAFT_CLIENT_SOURCES
|
|||
"Windows64/Windows64_App.cpp"
|
||||
"Windows64/Windows64_Minecraft.cpp"
|
||||
"Windows64/Network/WinsockNetLayer.cpp"
|
||||
"../Minecraft.Server/Core/ServerThreadPool.cpp"
|
||||
"Windows64/Audio/VoiceChat.cpp"
|
||||
"Windows64/KBMConfig.cpp"
|
||||
"KeyboardMouseInput.cpp"
|
||||
|
|
|
|||
Loading…
Reference in a new issue