fix: Minecraft Store 1; feat: Community-Made Packs integration
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
#include "UIScene_DLCMainMenu.h"
|
||||
|
||||
UIScene_DLCMainMenu::UIScene_DLCMainMenu(int iPad, void* initData, UILayer* parentLayer)
|
||||
: UIScene(iPad, parentLayer)
|
||||
: UIScene(iPad, parentLayer)
|
||||
{
|
||||
initialiseMovie();
|
||||
app.SetLiveLinkRequired(true);
|
||||
@@ -14,10 +14,11 @@ UIScene_DLCMainMenu::UIScene_DLCMainMenu(int iPad, void* initData, UILayer* pare
|
||||
if(m_loadedResolution == eSceneResolution_1080)
|
||||
m_labelXboxStore.init(L"");
|
||||
|
||||
m_buttonListOffers.addItem(L"All Packs", 0);
|
||||
m_buttonListOffers.addItem(L"Skin Packs", 1);
|
||||
m_buttonListOffers.addItem(L"Texture Packs", 2);
|
||||
m_buttonListOffers.addItem(L"Mash-up Packs", 3);
|
||||
m_buttonListOffers.addItem(L"All Packs", 0);
|
||||
m_buttonListOffers.addItem(L"Skin Packs", 1);
|
||||
m_buttonListOffers.addItem(L"Texture Packs", 2);
|
||||
m_buttonListOffers.addItem(L"Mash-up Packs", 3);
|
||||
m_buttonListOffers.addItem(L"Community-Made Packs", 4);
|
||||
m_buttonListOffers.setFocus(true);
|
||||
|
||||
m_Timer.setVisible(false);
|
||||
@@ -70,6 +71,7 @@ void UIScene_DLCMainMenu::handlePress(F64 controlId, F64 childId)
|
||||
DLCOffersParam* param = new DLCOffersParam();
|
||||
param->iPad = m_iPad;
|
||||
param->iType = static_cast<int>(childId);
|
||||
|
||||
ui.NavigateToScene(m_iPad, eUIScene_DLCOffersMenu, param);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "UIScene.h"
|
||||
|
||||
class UIScene_DLCMainMenu : public UIScene
|
||||
@@ -11,40 +10,39 @@ private:
|
||||
};
|
||||
|
||||
UIControl_DynamicButtonList m_buttonListOffers;
|
||||
UIControl_Label m_labelOffers, m_labelXboxStore;
|
||||
UIControl m_Timer;
|
||||
UIControl_Label m_labelOffers, m_labelXboxStore;
|
||||
UIControl m_Timer;
|
||||
|
||||
UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene)
|
||||
UI_MAP_ELEMENT( m_buttonListOffers, "OffersList")
|
||||
UI_MAP_ELEMENT( m_labelOffers, "OffersList_Title")
|
||||
UI_MAP_ELEMENT( m_Timer, "Timer")
|
||||
UI_MAP_ELEMENT(m_buttonListOffers, "OffersList")
|
||||
UI_MAP_ELEMENT(m_labelOffers, "OffersList_Title")
|
||||
UI_MAP_ELEMENT(m_Timer, "Timer")
|
||||
if(m_loadedResolution == eSceneResolution_1080)
|
||||
{
|
||||
UI_MAP_ELEMENT( m_labelXboxStore, "XboxLabel" )
|
||||
UI_MAP_ELEMENT(m_labelXboxStore, "XboxLabel")
|
||||
}
|
||||
UI_END_MAP_ELEMENTS_AND_NAMES()
|
||||
|
||||
static int ExitDLCMainMenu(void *pParam,int iPad,C4JStorage::EMessageResult result);
|
||||
static int ExitDLCMainMenu(void* pParam, int iPad, C4JStorage::EMessageResult result);
|
||||
|
||||
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__)
|
||||
bool m_bCategoriesShown;
|
||||
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
|
||||
bool m_bCategoriesShown;
|
||||
#endif
|
||||
|
||||
public:
|
||||
UIScene_DLCMainMenu(int iPad, void *initData, UILayer *parentLayer);
|
||||
UIScene_DLCMainMenu(int iPad, void* initData, UILayer* parentLayer);
|
||||
~UIScene_DLCMainMenu();
|
||||
virtual void handleTimerComplete(int id);
|
||||
virtual void handleGainFocus(bool navBack);
|
||||
|
||||
virtual EUIScene getSceneType() { return eUIScene_DLCMainMenu;}
|
||||
virtual void tick();
|
||||
virtual void updateTooltips();
|
||||
virtual void handleTimerComplete(int id);
|
||||
virtual void handleGainFocus(bool navBack);
|
||||
virtual EUIScene getSceneType() { return eUIScene_DLCMainMenu; }
|
||||
virtual void tick();
|
||||
virtual void updateTooltips();
|
||||
|
||||
protected:
|
||||
// TODO: This should be pure virtual in this class
|
||||
virtual wstring getMoviePath();
|
||||
|
||||
public:
|
||||
// INPUT
|
||||
virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled);
|
||||
virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool& handled);
|
||||
virtual void handlePress(F64 controlId, F64 childId);
|
||||
};
|
||||
};
|
||||
@@ -2,13 +2,44 @@
|
||||
#include "UI.h"
|
||||
#include "UIScene_DLCOffersMenu.h"
|
||||
#include "../../../Minecraft.World/StringHelpers.h"
|
||||
#include <wininet.h>
|
||||
#include <winhttp.h>
|
||||
#pragma comment(lib, "winhttp.lib")
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct LCEZipLocalHeader
|
||||
{
|
||||
DWORD sig;
|
||||
WORD verNeeded;
|
||||
WORD flags;
|
||||
WORD method;
|
||||
WORD modTime;
|
||||
WORD modDate;
|
||||
DWORD crc32;
|
||||
DWORD compSize;
|
||||
DWORD uncompSize;
|
||||
WORD fileNameLen;
|
||||
WORD extraLen;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct LCEZipEntry
|
||||
{
|
||||
std::string fname;
|
||||
WORD method;
|
||||
DWORD compSize;
|
||||
DWORD uncompSize;
|
||||
const BYTE* fileData;
|
||||
};
|
||||
|
||||
#include "miniz.h"
|
||||
#include "miniz.c"
|
||||
#pragma comment(lib, "wininet.lib")
|
||||
|
||||
static const char* WORKSHOP_REGISTRY_URL = "https://network-server-7kuc.onrender.com/workshop/registry.json";
|
||||
static const char* WORKSHOP_RAW_BASE = "https://network-server-7kuc.onrender.com/workshop";
|
||||
static const char* WORKSHOP_REGISTRY_URL = "https://network-server-7kuc.onrender.com/workshop/registry.json";
|
||||
static const char* WORKSHOP_RAW_BASE = "https://network-server-7kuc.onrender.com/workshop";
|
||||
static const char* COMMUNITY_REGISTRY_LOCAL = "http://localhost:7601/registry.json";
|
||||
static const char* COMMUNITY_RAW_BASE_LOCAL = "http://localhost:7601";
|
||||
static const char* COMMUNITY_REGISTRY_REMOTE = "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main/registry.json";
|
||||
static const char* COMMUNITY_RAW_BASE_REMOTE = "https://github.com/LCE-Hub/LCE-Workshop/raw/refs/heads/main";
|
||||
|
||||
const char* UIScene_DLCOffersMenu::CategoryForIndex(int index)
|
||||
{
|
||||
@@ -17,7 +48,7 @@ const char* UIScene_DLCOffersMenu::CategoryForIndex(int index)
|
||||
case 1: return "Skin";
|
||||
case 2: return "Texture";
|
||||
case 3: return "Mashup";
|
||||
case 4: return "Mod";
|
||||
case 4: return nullptr;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -25,17 +56,51 @@ const char* UIScene_DLCOffersMenu::CategoryForIndex(int index)
|
||||
bool UIScene_DLCOffersMenu::FetchURL(const std::string& url, std::vector<BYTE>& outData)
|
||||
{
|
||||
outData.clear();
|
||||
HINTERNET hInet = InternetOpenA("LCEWorkshop/1.0", INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0);
|
||||
if(!hInet) return false;
|
||||
HINTERNET hUrl = InternetOpenUrlA(hInet, url.c_str(), nullptr, 0,
|
||||
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_SECURE, 0);
|
||||
if(!hUrl) { InternetCloseHandle(hInet); return false; }
|
||||
BYTE buf[8192];
|
||||
|
||||
bool isHttps = (url.size() >= 8 && _strnicmp(url.c_str(), "https://", 8) == 0);
|
||||
const char* hostStart = url.c_str() + (isHttps ? 8 : 7);
|
||||
const char* pathStart = strchr(hostStart, '/');
|
||||
|
||||
std::string host = pathStart ? std::string(hostStart, pathStart - hostStart) : std::string(hostStart);
|
||||
std::string path = pathStart ? std::string(pathStart) : "/";
|
||||
|
||||
int port = isHttps ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
|
||||
|
||||
std::wstring wHost(host.begin(), host.end());
|
||||
std::wstring wPath(path.begin(), path.end());
|
||||
|
||||
HINTERNET hSession = WinHttpOpen(L"LCEWorkshop/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
|
||||
if(!hSession) return false;
|
||||
|
||||
HINTERNET hConnect = WinHttpConnect(hSession, wHost.c_str(), static_cast<INTERNET_PORT>(port), 0);
|
||||
if(!hConnect) { WinHttpCloseHandle(hSession); return false; }
|
||||
|
||||
DWORD flags = isHttps ? WINHTTP_FLAG_SECURE : 0;
|
||||
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", wPath.c_str(), nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
|
||||
if(!hRequest) { WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return false; }
|
||||
|
||||
DWORD redirectPolicy = WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS;
|
||||
WinHttpSetOption(hRequest, WINHTTP_OPTION_REDIRECT_POLICY, &redirectPolicy, sizeof(redirectPolicy));
|
||||
|
||||
bool sent = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) != FALSE;
|
||||
if(sent) sent = WinHttpReceiveResponse(hRequest, nullptr) != FALSE;
|
||||
|
||||
if(!sent) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return false; }
|
||||
|
||||
DWORD statusCode = 0;
|
||||
DWORD statusSize = sizeof(statusCode);
|
||||
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusSize, WINHTTP_NO_HEADER_INDEX);
|
||||
|
||||
if(statusCode != 200) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return false; }
|
||||
|
||||
BYTE buf[65536];
|
||||
DWORD dwRead = 0;
|
||||
while(InternetReadFile(hUrl, buf, sizeof(buf), &dwRead) && dwRead > 0)
|
||||
while(WinHttpReadData(hRequest, buf, sizeof(buf), &dwRead) && dwRead > 0)
|
||||
outData.insert(outData.end(), buf, buf + dwRead);
|
||||
InternetCloseHandle(hUrl);
|
||||
InternetCloseHandle(hInet);
|
||||
|
||||
WinHttpCloseHandle(hRequest);
|
||||
WinHttpCloseHandle(hConnect);
|
||||
WinHttpCloseHandle(hSession);
|
||||
return !outData.empty();
|
||||
}
|
||||
|
||||
@@ -68,31 +133,14 @@ static void EnsureDirExists(const std::string& path)
|
||||
CreateDirectoryA(path.c_str(), nullptr);
|
||||
}
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct ZipLocalHeader
|
||||
{
|
||||
DWORD sig;
|
||||
WORD verNeeded;
|
||||
WORD flags;
|
||||
WORD method;
|
||||
WORD modTime;
|
||||
WORD modDate;
|
||||
DWORD crc32;
|
||||
DWORD compSize;
|
||||
DWORD uncompSize;
|
||||
WORD fileNameLen;
|
||||
WORD extraLen;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static bool InflateBuffer(const BYTE* in, DWORD inSize, std::vector<BYTE>& out, DWORD uncompSize)
|
||||
{
|
||||
out.resize(uncompSize);
|
||||
mz_stream strm = {};
|
||||
strm.next_in = in;
|
||||
strm.avail_in = inSize;
|
||||
strm.next_out = out.data();
|
||||
strm.avail_out = uncompSize;
|
||||
mz_stream strm = {};
|
||||
strm.next_in = reinterpret_cast<const unsigned char*>(in);
|
||||
strm.avail_in = static_cast<mz_uint32>(inSize);
|
||||
strm.next_out = reinterpret_cast<unsigned char*>(out.data());
|
||||
strm.avail_out = static_cast<mz_uint32>(uncompSize);
|
||||
if(mz_inflateInit2(&strm, -15) != MZ_OK) return false;
|
||||
int ret = mz_inflate(&strm, MZ_FINISH);
|
||||
mz_inflateEnd(&strm);
|
||||
@@ -100,48 +148,102 @@ static bool InflateBuffer(const BYTE* in, DWORD inSize, std::vector<BYTE>& out,
|
||||
return ret == MZ_STREAM_END;
|
||||
}
|
||||
|
||||
bool UIScene_DLCOffersMenu::InstallPack(const std::vector<BYTE>& zipData, const std::string& packName)
|
||||
static std::vector<LCEZipEntry> CollectEntries(const std::vector<BYTE>& zipData)
|
||||
{
|
||||
std::vector<LCEZipEntry> entries;
|
||||
const BYTE* base = zipData.data();
|
||||
const BYTE* p = base;
|
||||
const BYTE* end = base + zipData.size();
|
||||
|
||||
while(p + sizeof(LCEZipLocalHeader) <= end)
|
||||
{
|
||||
const LCEZipLocalHeader* hdr = reinterpret_cast<const LCEZipLocalHeader*>(p);
|
||||
if(hdr->sig == 0x02014b50 || hdr->sig == 0x06054b50) break;
|
||||
if(hdr->sig != 0x04034b50) break;
|
||||
|
||||
WORD flags = hdr->flags;
|
||||
WORD method = hdr->method;
|
||||
DWORD compSize = hdr->compSize;
|
||||
DWORD uncompSize = hdr->uncompSize;
|
||||
WORD fnLen = hdr->fileNameLen;
|
||||
WORD exLen = hdr->extraLen;
|
||||
|
||||
p += sizeof(LCEZipLocalHeader);
|
||||
if(p + fnLen + exLen > end) break;
|
||||
|
||||
LCEZipEntry e;
|
||||
e.fname.assign(reinterpret_cast<const char*>(p), fnLen);
|
||||
p += fnLen + exLen;
|
||||
|
||||
e.method = method;
|
||||
e.compSize = compSize;
|
||||
e.uncompSize = uncompSize;
|
||||
e.fileData = p;
|
||||
|
||||
if(flags & 0x0008)
|
||||
{
|
||||
if(method == 0)
|
||||
{
|
||||
compSize = uncompSize;
|
||||
e.compSize = compSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
const BYTE* scan = p;
|
||||
while(scan + 4 <= end)
|
||||
{
|
||||
DWORD sig = *reinterpret_cast<const DWORD*>(scan);
|
||||
if(sig == 0x08074b50 || sig == 0x04034b50 || sig == 0x02014b50)
|
||||
{
|
||||
compSize = static_cast<DWORD>(scan - p);
|
||||
e.compSize = compSize;
|
||||
break;
|
||||
}
|
||||
++scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p + e.compSize > end) break;
|
||||
p += e.compSize;
|
||||
|
||||
if(flags & 0x0008)
|
||||
{
|
||||
if(p + 4 <= end && *reinterpret_cast<const DWORD*>(p) == 0x08074b50)
|
||||
p += 16;
|
||||
else if(p + 12 <= end)
|
||||
p += 12;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < e.fname.size(); i++)
|
||||
if(e.fname[i] == '/') e.fname[i] = '\\';
|
||||
|
||||
if(!e.fname.empty())
|
||||
entries.push_back(e);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
bool UIScene_DLCOffersMenu::InstallPack(const std::vector<BYTE>& zipData, const std::string& packName, bool isCommunity)
|
||||
{
|
||||
if(zipData.empty()) return false;
|
||||
|
||||
std::string baseDir = GetGameDir() + "Windows64Media\\DLC\\" + packName + "\\";
|
||||
EnsureDirExists(baseDir);
|
||||
std::string outDir = isCommunity
|
||||
? GetGameDir() + "Windows64Media\\DLC\\"
|
||||
: GetGameDir() + "Windows64Media\\DLC\\" + packName + "\\";
|
||||
EnsureDirExists(outDir);
|
||||
|
||||
const BYTE* p = zipData.data();
|
||||
const BYTE* end = p + zipData.size();
|
||||
int extracted = 0;
|
||||
std::vector<LCEZipEntry> entries = CollectEntries(zipData);
|
||||
if(entries.empty()) return false;
|
||||
|
||||
while(p + sizeof(ZipLocalHeader) <= end)
|
||||
int extracted = 0;
|
||||
|
||||
for(size_t i = 0; i < entries.size(); i++)
|
||||
{
|
||||
const ZipLocalHeader* hdr = reinterpret_cast<const ZipLocalHeader*>(p);
|
||||
const LCEZipEntry& e = entries[i];
|
||||
if(e.fname.empty() || e.fname[e.fname.size() - 1] == '\\') continue;
|
||||
|
||||
if(hdr->sig == 0x02014b50 || hdr->sig == 0x06054b50)
|
||||
break;
|
||||
if(hdr->sig != 0x04034b50)
|
||||
break;
|
||||
|
||||
p += sizeof(ZipLocalHeader);
|
||||
if(p + hdr->fileNameLen + hdr->extraLen > end) break;
|
||||
|
||||
std::string fname(reinterpret_cast<const char*>(p), hdr->fileNameLen);
|
||||
p += hdr->fileNameLen + hdr->extraLen;
|
||||
|
||||
if(p + hdr->compSize > end) break;
|
||||
const BYTE* fileData = p;
|
||||
p += hdr->compSize;
|
||||
|
||||
if(fname.empty() || fname.back() == '/' || fname.back() == '\\')
|
||||
continue;
|
||||
|
||||
for(char& c : fname) if(c == '/') c = '\\';
|
||||
|
||||
size_t firstSlash = fname.find('\\');
|
||||
if(firstSlash != std::string::npos)
|
||||
fname = fname.substr(firstSlash + 1);
|
||||
|
||||
if(fname.empty()) continue;
|
||||
|
||||
std::string outPath = baseDir + fname;
|
||||
std::string outPath = outDir + e.fname;
|
||||
|
||||
size_t lastSlash = outPath.rfind('\\');
|
||||
if(lastSlash != std::string::npos)
|
||||
@@ -150,14 +252,14 @@ bool UIScene_DLCOffersMenu::InstallPack(const std::vector<BYTE>& zipData, const
|
||||
std::vector<BYTE> outBuf;
|
||||
bool ok = false;
|
||||
|
||||
if(hdr->method == 0)
|
||||
if(e.method == 0)
|
||||
{
|
||||
outBuf.assign(fileData, fileData + hdr->compSize);
|
||||
outBuf.assign(e.fileData, e.fileData + e.compSize);
|
||||
ok = true;
|
||||
}
|
||||
else if(hdr->method == 8)
|
||||
else if(e.method == 8)
|
||||
{
|
||||
ok = InflateBuffer(fileData, hdr->compSize, outBuf, hdr->uncompSize);
|
||||
ok = InflateBuffer(e.fileData, e.compSize, outBuf, e.uncompSize);
|
||||
}
|
||||
|
||||
if(ok && !outBuf.empty())
|
||||
@@ -229,7 +331,7 @@ static void SkipValue(const char*& p)
|
||||
while(*p && *p != ',' && *p != '}' && *p != ']') ++p;
|
||||
}
|
||||
|
||||
bool UIScene_DLCOffersMenu::ParseRegistry(const std::string& json)
|
||||
bool UIScene_DLCOffersMenu::ParseRegistry(const std::string& json, const std::string& rawBase)
|
||||
{
|
||||
m_packs.clear();
|
||||
const char* p = json.c_str();
|
||||
@@ -308,8 +410,14 @@ bool UIScene_DLCOffersMenu::ParseRegistry(const std::string& json)
|
||||
}
|
||||
if(*p == '}') ++p;
|
||||
|
||||
bool allDLC = !pack.zips.empty();
|
||||
for(int i = 0; i < (int)pack.zips.size(); i++)
|
||||
if(pack.zips[i].destToken != "{DLCDir}") { allDLC = false; break; }
|
||||
|
||||
if(!allDLC) continue;
|
||||
|
||||
if(!pack.id.empty() && !thumbFile.empty())
|
||||
pack.thumbnailUrl = std::string(WORKSHOP_RAW_BASE) + "/" + pack.id + "/" + thumbFile;
|
||||
pack.thumbnailUrl = rawBase + "/" + pack.id + "/" + thumbFile;
|
||||
|
||||
if(!pack.id.empty())
|
||||
m_packs.push_back(pack);
|
||||
@@ -321,6 +429,7 @@ bool UIScene_DLCOffersMenu::ParseRegistry(const std::string& json)
|
||||
UIScene_DLCOffersMenu::UIScene_DLCOffersMenu(int iPad, void* initData, UILayer* parentLayer)
|
||||
: UIScene(iPad, parentLayer)
|
||||
, m_eFetchState(eFetch_Idle)
|
||||
, m_bIsCommunity(false)
|
||||
, m_iCurrentPack(0)
|
||||
, m_iProductInfoIndex(0)
|
||||
, m_bIsSD(false)
|
||||
@@ -329,6 +438,7 @@ UIScene_DLCOffersMenu::UIScene_DLCOffersMenu(int iPad, void* initData, UILayer*
|
||||
{
|
||||
DLCOffersParam* param = static_cast<DLCOffersParam*>(initData);
|
||||
m_iProductInfoIndex = param ? param->iType : 0;
|
||||
m_bIsCommunity = (m_iProductInfoIndex == 4);
|
||||
|
||||
initialiseMovie();
|
||||
app.SetLiveLinkRequired(true);
|
||||
@@ -362,13 +472,42 @@ void UIScene_DLCOffersMenu::tick()
|
||||
|
||||
m_eFetchState = eFetch_Error;
|
||||
|
||||
char urlWithBust[512];
|
||||
snprintf(urlWithBust, sizeof(urlWithBust), "%s?_=%llu",
|
||||
WORKSHOP_REGISTRY_URL,
|
||||
static_cast<unsigned long long>(GetTickCount64()));
|
||||
|
||||
std::string jsonStr;
|
||||
if(!FetchURLString(urlWithBust, jsonStr) || !ParseRegistry(jsonStr))
|
||||
|
||||
if(m_bIsCommunity)
|
||||
{
|
||||
if(FetchURLString(COMMUNITY_REGISTRY_LOCAL, jsonStr))
|
||||
{
|
||||
m_rawBase = COMMUNITY_RAW_BASE_LOCAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!FetchURLString(COMMUNITY_REGISTRY_REMOTE, jsonStr))
|
||||
{
|
||||
m_labelOffers.setLabel(app.GetString(IDS_NO_DLCCATEGORIES));
|
||||
m_Timer.setVisible(false);
|
||||
return;
|
||||
}
|
||||
m_rawBase = COMMUNITY_RAW_BASE_REMOTE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char urlWithBust[512];
|
||||
snprintf(urlWithBust, sizeof(urlWithBust), "%s?_=%llu",
|
||||
WORKSHOP_REGISTRY_URL,
|
||||
static_cast<unsigned long long>(GetTickCount64()));
|
||||
|
||||
if(!FetchURLString(urlWithBust, jsonStr))
|
||||
{
|
||||
m_labelOffers.setLabel(app.GetString(IDS_NO_DLCCATEGORIES));
|
||||
m_Timer.setVisible(false);
|
||||
return;
|
||||
}
|
||||
m_rawBase = WORKSHOP_RAW_BASE;
|
||||
}
|
||||
|
||||
if(!ParseRegistry(jsonStr, m_rawBase))
|
||||
{
|
||||
m_labelOffers.setLabel(app.GetString(IDS_NO_DLCCATEGORIES));
|
||||
m_Timer.setVisible(false);
|
||||
@@ -500,7 +639,7 @@ void UIScene_DLCOffersMenu::handlePress(F64 controlId, F64 childId)
|
||||
m_Timer.setVisible(true);
|
||||
|
||||
const WorkshopZip& zip = pk->zips[0];
|
||||
std::string zipUrl = std::string(WORKSHOP_RAW_BASE) + "/" + pk->id + "/" + zip.filename;
|
||||
std::string zipUrl = m_rawBase + "/" + pk->id + "/" + zip.filename;
|
||||
|
||||
std::vector<BYTE> zipData;
|
||||
if(!FetchURL(zipUrl, zipData) || zipData.empty())
|
||||
@@ -509,7 +648,7 @@ void UIScene_DLCOffersMenu::handlePress(F64 controlId, F64 childId)
|
||||
return;
|
||||
}
|
||||
|
||||
bool installed = InstallPack(zipData, packName);
|
||||
bool installed = InstallPack(zipData, packName, m_bIsCommunity);
|
||||
m_Timer.setVisible(false);
|
||||
|
||||
if(installed)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
#include "UIScene.h"
|
||||
|
||||
struct WorkshopZip
|
||||
{
|
||||
std::string filename;
|
||||
std::string destToken;
|
||||
};
|
||||
|
||||
struct WorkshopPack
|
||||
{
|
||||
std::string id;
|
||||
@@ -17,21 +19,27 @@ struct WorkshopPack
|
||||
std::string version;
|
||||
std::vector<BYTE> thumbnailData;
|
||||
bool thumbnailLoaded;
|
||||
|
||||
WorkshopPack() : thumbnailLoaded(false) {}
|
||||
};
|
||||
|
||||
class UIScene_DLCOffersMenu : public UIScene
|
||||
{
|
||||
private:
|
||||
enum EControls { eControl_OffersList };
|
||||
enum EControls { eControl_OffersList };
|
||||
enum EFetchState { eFetch_Idle, eFetch_Ready, eFetch_Error };
|
||||
|
||||
bool m_bIsSD;
|
||||
bool m_bHasPurchased;
|
||||
bool m_bIsSelected;
|
||||
bool m_bIsCommunity;
|
||||
|
||||
UIControl_DLCList m_buttonListOffers;
|
||||
UIControl_Label m_labelOffers, m_labelPriceTag, m_labelXboxStore;
|
||||
UIControl_HTMLLabel m_labelHTMLSellText;
|
||||
UIControl_BitmapIcon m_bitmapIconOfferImage;
|
||||
UIControl m_Timer;
|
||||
|
||||
UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene)
|
||||
UI_MAP_ELEMENT(m_buttonListOffers, "OffersList")
|
||||
UI_MAP_ELEMENT(m_labelOffers, "OffersList_Title")
|
||||
@@ -44,28 +52,35 @@ private:
|
||||
UI_MAP_ELEMENT(m_labelXboxStore, "XboxLabel")
|
||||
}
|
||||
UI_END_MAP_ELEMENTS_AND_NAMES()
|
||||
|
||||
EFetchState m_eFetchState;
|
||||
std::string m_rawBase;
|
||||
std::vector<WorkshopPack> m_packs;
|
||||
std::vector<WorkshopPack*> m_filteredPacks;
|
||||
int m_iCurrentPack;
|
||||
int m_iProductInfoIndex;
|
||||
|
||||
static const char* CategoryForIndex(int index);
|
||||
static bool FetchURL(const std::string& url, std::vector<BYTE>& outData);
|
||||
static bool FetchURLString(const std::string& url, std::string& outStr);
|
||||
bool ParseRegistry(const std::string& json);
|
||||
bool ParseRegistry(const std::string& json, const std::string& rawBase);
|
||||
void PopulateList();
|
||||
void UpdateDetailPanel();
|
||||
static bool InstallPack(const std::vector<BYTE>& zipData, const std::string& packName);
|
||||
static bool InstallPack(const std::vector<BYTE>& zipData, const std::string& packName, bool isCommunity);
|
||||
static bool IsPackInstalled(const std::string& packName);
|
||||
|
||||
public:
|
||||
UIScene_DLCOffersMenu(int iPad, void* initData, UILayer* parentLayer);
|
||||
~UIScene_DLCOffersMenu();
|
||||
|
||||
static int ExitDLCOffersMenu(void* pParam, int iPad, C4JStorage::EMessageResult result);
|
||||
virtual EUIScene getSceneType() { return eUIScene_DLCOffersMenu; }
|
||||
virtual void tick();
|
||||
virtual void updateTooltips();
|
||||
|
||||
protected:
|
||||
virtual wstring getMoviePath();
|
||||
|
||||
public:
|
||||
virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool& handled);
|
||||
virtual void handlePress(F64 controlId, F64 childId);
|
||||
|
||||
Reference in New Issue
Block a user