Merge branch '4jcraft:dev' into feat/text-input-support

This commit is contained in:
MatthewBeshay 2026-03-30 13:22:48 +11:00 committed by GitHub
commit fe4c9bd36c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 424 additions and 625 deletions

View file

@ -1,6 +1,6 @@
#include "../../Minecraft.World/Platform/stdafx.h" #include "../../Minecraft.World/Platform/stdafx.h"
#include "SoundEngine.h" #include "SoundEngine.h"
#include "PathHelper.h"
#include "../Consoles_App.h" #include "../Consoles_App.h"
#include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h" #include "../../Minecraft.Client/Player/MultiPlayerLocalPlayer.h"
#include "../../Minecraft.World/Headers/net.minecraft.world.level.h" #include "../../Minecraft.World/Headers/net.minecraft.world.level.h"
@ -82,8 +82,8 @@ const char* SoundEngine::m_szStreamFileA[eStream_Max] = {"calm1",
"ward", "ward",
"where_are_we_now"}; "where_are_we_now"};
#ifdef __linux__ #ifdef __linux__
char SoundEngine::m_szSoundPath[] = {"Sound/"}; char SoundEngine::m_szSoundPath[] = {"Common/Sound/"};
char SoundEngine::m_szMusicPath[] = {"music/"}; char SoundEngine::m_szMusicPath[] = {"Common/"};
char SoundEngine::m_szRedistName[] = {"redist64"}; char SoundEngine::m_szRedistName[] = {"redist64"};
#endif #endif
@ -188,170 +188,121 @@ void SoundEngine::init(Options* pOptions) {
m_bSystemMusicPlaying = false; m_bSystemMusicPlaying = false;
} }
void SoundEngine::destroy() { ma_engine_uninit(&m_engine); } void SoundEngine::destroy() { ma_engine_uninit(&m_engine); }
void SoundEngine::play(int iSound, float x, float y, float z, float volume, void SoundEngine::play(int iSound, float x, float y, float z, float volume,
float pitch) { float pitch) {
char szSoundName[256] = "Sound/Minecraft/"; if (iSound == -1) return;
char szId[256];
wcstombs(szId, wchSoundNames[iSound], 255);
for (int i = 0; szId[i]; i++)
if (szId[i] == '.') szId[i] = '/';
if (iSound == -1) { std::string base = PathHelper::GetExecutableDirA() + "/";
app.DebugPrintf(6, "PlaySound with sound of -1 !!!!!!!!!!!!!!!\n"); const char* roots[] = {"Sound/Minecraft/", "Common/Sound/Minecraft/",
return; "Common/res/TitleUpdate/res/Sound/Minecraft/"};
} char finalPath[512] = {0};
wcstombs(szSoundName + 16, wchSoundNames[iSound],
sizeof(szSoundName) - 16 - 1);
szSoundName[sizeof(szSoundName) - 1] = '\0';
char finalPath[256];
const char* extensions[] = {".ogg", ".wav", ".mp3"};
size_t extCount = sizeof(extensions) / sizeof(extensions[0]);
bool found = false; bool found = false;
for (size_t extIdx = 0; extIdx < extCount; extIdx++) { for (const char* root : roots) {
char basePlusExt[256]; std::string fullRoot = base + root;
sprintf_s(basePlusExt, "%s%s", szSoundName, extensions[extIdx]); for (const char* ext : {".ogg", ".wav"}) {
int count = 0;
DWORD attr = GetFileAttributesA(basePlusExt); for (int i = 1; i <= 16; i++) {
if (attr != INVALID_FILE_ATTRIBUTES && char tryP[512];
!(attr & FILE_ATTRIBUTE_DIRECTORY)) { snprintf(tryP, 512, "%s%s%d%s", fullRoot.c_str(), szId, i, ext);
sprintf_s(finalPath, "%s", basePlusExt); if (access(tryP, F_OK) != -1)
found = true;
break;
}
}
if (!found) {
int count = 0;
for (size_t extIdx = 0; extIdx < extCount; extIdx++) {
for (size_t i = 1; i < 32; i++) {
char numberedPath[256];
sprintf_s(numberedPath, "%s%d%s", szSoundName, i,
extensions[extIdx]);
DWORD attr = GetFileAttributesA(numberedPath);
if (attr != INVALID_FILE_ATTRIBUTES &&
!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
count = i; count = i;
} else
}
}
if (count > 0) {
int chosen = (rand() % count) + 1;
for (size_t extIdx = 0; extIdx < extCount; extIdx++) {
char numberedPath[256];
sprintf_s(numberedPath, "%s%d%s", szSoundName, chosen,
extensions[extIdx]);
DWORD attr = GetFileAttributesA(numberedPath);
if (attr != INVALID_FILE_ATTRIBUTES &&
!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
sprintf_s(finalPath, "%s", numberedPath);
found = true;
break; break;
}
} }
if (!found) { if (count > 0) {
sprintf_s(finalPath, "%s%d.ogg", szSoundName, chosen); snprintf(finalPath, 512, "%s%s%d%s", fullRoot.c_str(), szId,
(rand() % count) + 1, ext);
found = true;
break;
}
char tryP[512];
snprintf(tryP, 512, "%s%s%s", fullRoot.c_str(), szId, ext);
if (access(tryP, F_OK) != -1) {
strncpy(finalPath, tryP, 511);
found = true;
break;
} }
} }
if (found) break;
} }
if (!found) return; if (!found) return;
MiniAudioSound* s = new MiniAudioSound(); MiniAudioSound* s = new MiniAudioSound();
memset(&s->info, 0, sizeof(AUDIO_INFO)); memset(&s->info, 0, sizeof(AUDIO_INFO));
s->info.x = x; s->info.x = x;
s->info.y = y; s->info.y = y;
s->info.z = z; s->info.z = z;
s->info.volume = volume; s->info.volume = volume;
s->info.pitch = pitch; s->info.pitch = pitch;
s->info.bIs3D = true; s->info.bIs3D = true;
s->info.bUseSoundsPitchVal = false;
s->info.iSound = iSound + eSFX_MAX;
if (ma_sound_init_from_file(&m_engine, finalPath, MA_SOUND_FLAG_ASYNC, if (ma_sound_init_from_file(&m_engine, finalPath, MA_SOUND_FLAG_ASYNC,
nullptr, nullptr, &s->sound) != MA_SUCCESS) { nullptr, nullptr, &s->sound) == MA_SUCCESS) {
app.DebugPrintf("Failed to load sound ID : %i from %S\n", iSound, ma_sound_set_spatialization_enabled(&s->sound, MA_TRUE);
wchSoundNames[iSound]); ma_sound_set_min_distance(&s->sound, 2.0f);
ma_sound_set_max_distance(&s->sound, 48.0f);
ma_sound_set_volume(&s->sound, volume * m_MasterEffectsVolume);
ma_sound_set_position(&s->sound, x, y, z);
ma_sound_start(&s->sound);
m_activeSounds.push_back(s);
} else
delete s; delete s;
return;
}
ma_sound_set_spatialization_enabled(&s->sound, MA_TRUE);
ma_sound_set_min_distance(&s->sound, SFX_3D_MIN_DISTANCE);
ma_sound_set_max_distance(&s->sound, SFX_3D_MAX_DISTANCE);
ma_sound_set_rolloff(&s->sound, SFX_3D_ROLLOFF);
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&s->sound, finalVolume);
ma_sound_set_pitch(&s->sound, pitch);
ma_sound_set_position(&s->sound, x, y, z);
ma_sound_start(&s->sound);
m_activeSounds.push_back(s);
} }
void SoundEngine::playUI(int iSound, float volume, float pitch) { void SoundEngine::playUI(int iSound, float volume, float pitch) {
char szSoundName[256]; char szIdentifier[256];
wstring name; if (iSound >= eSFX_MAX)
wcstombs(szIdentifier, wchSoundNames[iSound], 255);
if (iSound >= eSFX_MAX) { else
strcpy(szSoundName, "Sound/Minecraft/"); wcstombs(szIdentifier, wchUISoundNames[iSound], 255);
name = wchSoundNames[iSound]; for (int i = 0; szIdentifier[i]; i++)
} else { if (szIdentifier[i] == '.') szIdentifier[i] = '/';
strcpy(szSoundName, "Sound/Minecraft/UI/"); std::string base = PathHelper::GetExecutableDirA() + "/";
name = wchUISoundNames[iSound]; const char* roots[] = {
} "Sound/Minecraft/UI/",
wcstombs(szSoundName + strlen(szSoundName), name.c_str(), "Sound/Minecraft/",
sizeof(szSoundName) - strlen(szSoundName) - 1); "Common/Sound/Minecraft/UI/",
char finalPath[256]; "Common/Sound/Minecraft/",
const char* extensions[] = {".ogg", ".wav", ".mp3"}; };
size_t extCount = sizeof(extensions) / sizeof(extensions[0]); char finalPath[512] = {0};
bool found = false; bool found = false;
for (size_t extIdx = 0; extIdx < extCount; extIdx++) { for (const char* root : roots) {
char basePlusExt[256]; for (const char* ext : {".ogg", ".wav", ".mp3"}) {
sprintf_s(basePlusExt, "%s%s", szSoundName, extensions[extIdx]); char tryP[512];
snprintf(tryP, 512, "%s%s%s%s", base.c_str(), root, szIdentifier,
DWORD attr = GetFileAttributesA(basePlusExt); ext);
if (attr != INVALID_FILE_ATTRIBUTES && if (access(tryP, F_OK) != -1) {
!(attr & FILE_ATTRIBUTE_DIRECTORY)) { strncpy(finalPath, tryP, 511);
sprintf_s(finalPath, "%s", basePlusExt); found = true;
found = true; break;
break; }
} }
if (found) break;
} }
if (!found) return; if (!found) return;
MiniAudioSound* s = new MiniAudioSound(); MiniAudioSound* s = new MiniAudioSound();
memset(&s->info, 0, sizeof(AUDIO_INFO)); memset(&s->info, 0, sizeof(AUDIO_INFO));
s->info.volume = volume; s->info.volume = volume;
s->info.pitch = pitch; s->info.pitch = pitch;
s->info.bIs3D = false; s->info.bIs3D = false;
s->info.bUseSoundsPitchVal = true;
if (ma_sound_init_from_file(&m_engine, finalPath, MA_SOUND_FLAG_ASYNC, if (ma_sound_init_from_file(&m_engine, finalPath, MA_SOUND_FLAG_ASYNC,
nullptr, nullptr, &s->sound) != MA_SUCCESS) { nullptr, nullptr, &s->sound) == MA_SUCCESS) {
ma_sound_set_spatialization_enabled(&s->sound, MA_FALSE);
ma_sound_set_volume(&s->sound, volume * m_MasterEffectsVolume);
ma_sound_set_pitch(&s->sound, pitch);
ma_sound_start(&s->sound);
m_activeSounds.push_back(s);
} else
delete s; delete s;
app.DebugPrintf("ma_sound_init_from_file failed: %s\n", finalPath);
return;
}
ma_sound_set_spatialization_enabled(&s->sound, MA_FALSE);
float finalVolume = volume * m_MasterEffectsVolume;
if (finalVolume > 1.0f) finalVolume = 1.0f;
printf("UI Sound volume set to %f\nEffects volume: %f\n", finalVolume,
m_MasterEffectsVolume);
ma_sound_set_volume(&s->sound, finalVolume);
ma_sound_set_pitch(&s->sound, pitch);
ma_sound_start(&s->sound);
m_activeSounds.push_back(s);
} }
int SoundEngine::getMusicID(int iDomain) { int SoundEngine::getMusicID(int iDomain) {
@ -368,9 +319,10 @@ int SoundEngine::getMusicID(int iDomain) {
if (pMinecraft->skins->isUsingDefaultSkin()) { if (pMinecraft->skins->isUsingDefaultSkin()) {
switch (iDomain) { switch (iDomain) {
case LevelData::DIMENSION_END: case LevelData::DIMENSION_END:
// the end isn't random - it has different music depending on // the end isn't random - it has different music depending
// whether the dragon is alive or not, but we've not added the // whether the dragon is alive or not, but we've not
// dead dragon music yet // added the dead dragon music yet
// haha they said wheter
return m_iStream_End_Min; return m_iStream_End_Min;
case LevelData::DIMENSION_NETHER: case LevelData::DIMENSION_NETHER:
return GetRandomishTrack(m_iStream_Nether_Min, return GetRandomishTrack(m_iStream_Nether_Min,
@ -488,7 +440,8 @@ int SoundEngine::OpenStreamThreadProc(void* lpParameter) {
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
app.DebugPrintf( app.DebugPrintf(
"SoundEngine::OpenStreamThreadProc - Failed to open stream: %s\n", "SoundEngine::OpenStreamThreadProc - Failed to open stream: "
"%s\n",
soundEngine->m_szStreamName); soundEngine->m_szStreamName);
return 0; return 0;
} }
@ -500,149 +453,63 @@ int SoundEngine::OpenStreamThreadProc(void* lpParameter) {
return 0; return 0;
} }
void SoundEngine::playMusicTick() { void SoundEngine::playMusicTick() {
static float fMusicVol = 0.0f; static float fMusicVol = 0.0f;
fMusicVol = getMasterMusicVolume(); fMusicVol = getMasterMusicVolume();
switch (m_StreamState) { switch (m_StreamState) {
case eMusicStreamState_Idle: case eMusicStreamState_Idle:
// start a stream playing
if (m_iMusicDelay > 0) { if (m_iMusicDelay > 0) {
m_iMusicDelay--; m_iMusicDelay--;
return; return;
} }
if (m_musicStreamActive) {
app.DebugPrintf(
"WARNING: m_musicStreamActive already true in Idle state, "
"resetting to Playing\n");
m_StreamState = eMusicStreamState_Playing;
return;
}
if (m_musicID != -1) { if (m_musicID != -1) {
// start playing it std::string base = PathHelper::GetExecutableDirA() + "/";
bool isCD = (m_musicID >= m_iStream_CD_1);
const char* folder = isCD ? "cds/" : "music/";
const char* track = m_szStreamFileA[m_musicID];
bool found = false;
m_szStreamName[0] = '\0';
strcpy((char*)m_szStreamName, m_szMusicPath); const char* roots[] = {"Common/music/", "music/", "./"};
// are we using a mash-up pack?
// if(pMinecraft && !pMinecraft->skins->isUsingDefaultSkin() &&
// pMinecraft->skins->getSelected()->hasAudio())
if (Minecraft::GetInstance()
->skins->getSelected()
->hasAudio()) {
// It's a mash-up - need to use the DLC path for the music
TexturePack* pTexPack =
Minecraft::GetInstance()->skins->getSelected();
DLCTexturePack* pDLCTexPack = (DLCTexturePack*)pTexPack;
DLCPack* pack = pDLCTexPack->getDLCInfoParentPack();
DLCAudioFile* dlcAudioFile = (DLCAudioFile*)pack->getFile(
DLCManager::e_DLCType_Audio, 0);
app.DebugPrintf("Mashup pack \n"); for (const char* r : roots) {
for (const char* e : {".ogg", ".mp3", ".wav"}) {
// build the name char c[512];
// try with folder prefix (music/ or cds/)
// if the music ID is beyond the end of the texture pack snprintf(c, 512, "%s%s%s%s%s", base.c_str(), r, folder,
// music files, then it's a CD track, e);
if (m_musicID < m_iStream_CD_1) { if (access(c, F_OK) != -1) {
SetIsPlayingStreamingGameMusic(true); strncpy(m_szStreamName, c, 511);
SetIsPlayingStreamingCDMusic(false); found = true;
m_MusicType = eMusicType_Game; break;
m_StreamingAudioInfo.bIs3D = false; }
// try without folder prefix
wstring& wstrSoundName = snprintf(c, 512, "%s%s%s%s", base.c_str(), r, track, e);
dlcAudioFile->GetSoundName(m_musicID); if (access(c, F_OK) != -1) {
strncpy(m_szStreamName, c, 511);
char szName[255]; found = true;
wcstombs(szName, wstrSoundName.c_str(), 255); break;
string strFile =
"TPACK:\\Data\\" + string(szName) + ".wav";
std::string mountedPath =
StorageManager.GetMountedPath(strFile);
strcpy(m_szStreamName, mountedPath.c_str());
} else {
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(true);
m_MusicType = eMusicType_CD;
m_StreamingAudioInfo.bIs3D = true;
// Need to adjust to index into the cds in the game's
// m_szStreamFileA
strcat((char*)m_szStreamName, "cds/");
strcat((char*)m_szStreamName,
m_szStreamFileA[m_musicID - m_iStream_CD_1 +
eStream_CD_1]);
strcat((char*)m_szStreamName, ".wav");
}
} else {
if (m_musicID < m_iStream_CD_1) {
SetIsPlayingStreamingGameMusic(true);
SetIsPlayingStreamingCDMusic(false);
m_MusicType = eMusicType_Game;
m_StreamingAudioInfo.bIs3D = false;
// build the name
strcat((char*)m_szStreamName, "music/");
} else {
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(true);
m_MusicType = eMusicType_CD;
m_StreamingAudioInfo.bIs3D = true;
// build the name
strcat((char*)m_szStreamName, "cds/");
}
strcat((char*)m_szStreamName, m_szStreamFileA[m_musicID]);
strcat((char*)m_szStreamName, ".wav");
}
FILE* pFile = nullptr;
pFile = fopen(reinterpret_cast<char*>(m_szStreamName), "rb");
if (pFile) {
fclose(pFile);
} else {
const char* extensions[] = {".ogg", ".mp3", ".wav"};
size_t extCount =
sizeof(extensions) / sizeof(extensions[0]);
bool found = false;
char* dotPos =
strrchr(reinterpret_cast<char*>(m_szStreamName), '.');
if (dotPos != nullptr &&
(dotPos - reinterpret_cast<char*>(m_szStreamName)) <
250) {
for (size_t i = 0; i < extCount; i++) {
strncpy(dotPos, extensions[i], 5);
app.DebugPrintf("Checking %s\n", m_szStreamName);
pFile = fopen(
reinterpret_cast<char*>(m_szStreamName), "rb");
if (pFile) {
fclose(pFile);
found = true;
break;
}
} }
} }
if (found) break;
if (!found) {
if (dotPos != nullptr) {
strncpy(dotPos, ".wav", 5);
}
app.DebugPrintf(
"WARNING: No audio file found for music ID %d "
"(tried .ogg, .mp3, .wav)\n",
m_musicID);
return;
}
} }
app.DebugPrintf("Starting streaming - %s\n", m_szStreamName); if (found) {
m_openStreamThread = new C4JThread(OpenStreamThreadProc, this, SetIsPlayingStreamingGameMusic(!isCD);
"OpenStreamThreadProc"); SetIsPlayingStreamingCDMusic(isCD);
m_openStreamThread->Run(); m_openStreamThread = new C4JThread(
m_StreamState = eMusicStreamState_Opening; OpenStreamThreadProc, this, "OpenStreamThreadProc");
m_openStreamThread->Run();
m_StreamState = eMusicStreamState_Opening;
} else {
app.DebugPrintf(
"[SoundEngine] oh noes couldn't find music track '%s', "
"retrying "
"in 1min\n",
track);
m_iMusicDelay = 20 * 60;
}
} }
break; break;
@ -651,64 +518,30 @@ void SoundEngine::playMusicTick() {
delete m_openStreamThread; delete m_openStreamThread;
m_openStreamThread = nullptr; m_openStreamThread = nullptr;
app.DebugPrintf(
"OpenStreamThreadProc finished. m_musicStreamActive=%d\n",
m_musicStreamActive);
if (!m_musicStreamActive) { if (!m_musicStreamActive) {
const char* currentExt =
strrchr(reinterpret_cast<char*>(m_szStreamName), '.');
if (currentExt && _stricmp(currentExt, ".wav") == 0) {
const bool isCD = (m_musicID >= m_iStream_CD_1);
const char* folder = isCD ? "cds/" : "music/";
int n =
sprintf_s(reinterpret_cast<char*>(m_szStreamName),
512, "%s%s%s.wav", m_szMusicPath, folder,
m_szStreamFileA[m_musicID]);
if (n > 0) {
FILE* pFile = fopen(
reinterpret_cast<char*>(m_szStreamName), "rb");
if (pFile) {
fclose(pFile);
m_openStreamThread =
new C4JThread(OpenStreamThreadProc, this,
"OpenStreamThreadProc");
m_openStreamThread->Run();
break;
}
}
}
m_StreamState = eMusicStreamState_Idle; m_StreamState = eMusicStreamState_Idle;
break; break;
} }
ma_sound_set_spatialization_enabled(
&m_musicStream,
m_StreamingAudioInfo.bIs3D ? MA_TRUE : MA_FALSE);
if (m_StreamingAudioInfo.bIs3D) { if (m_StreamingAudioInfo.bIs3D) {
ma_sound_set_spatialization_enabled(&m_musicStream,
MA_TRUE);
ma_sound_set_position( ma_sound_set_position(
&m_musicStream, m_StreamingAudioInfo.x, &m_musicStream, m_StreamingAudioInfo.x,
m_StreamingAudioInfo.y, m_StreamingAudioInfo.z); m_StreamingAudioInfo.y, m_StreamingAudioInfo.z);
} else {
ma_sound_set_spatialization_enabled(&m_musicStream,
MA_FALSE);
} }
ma_sound_set_pitch(&m_musicStream, m_StreamingAudioInfo.pitch); ma_sound_set_pitch(&m_musicStream, m_StreamingAudioInfo.pitch);
ma_sound_set_volume(
float finalVolume = &m_musicStream,
m_StreamingAudioInfo.volume * getMasterMusicVolume(); m_StreamingAudioInfo.volume * getMasterMusicVolume());
ma_sound_start(&m_musicStream);
ma_sound_set_volume(&m_musicStream, finalVolume);
ma_result startResult = ma_sound_start(&m_musicStream);
app.DebugPrintf("ma_sound_start result: %d\n", startResult);
m_StreamState = eMusicStreamState_Playing; m_StreamState = eMusicStreamState_Playing;
} }
break; break;
case eMusicStreamState_OpeningCancel: case eMusicStreamState_OpeningCancel:
if (!m_openStreamThread->isRunning()) { if (!m_openStreamThread->isRunning()) {
delete m_openStreamThread; delete m_openStreamThread;
@ -716,200 +549,130 @@ void SoundEngine::playMusicTick() {
m_StreamState = eMusicStreamState_Stop; m_StreamState = eMusicStreamState_Stop;
} }
break; break;
case eMusicStreamState_Stop: case eMusicStreamState_Stop:
if (m_musicStreamActive) { if (m_musicStreamActive) {
ma_sound_stop(&m_musicStream); ma_sound_stop(&m_musicStream);
ma_sound_uninit(&m_musicStream); ma_sound_uninit(&m_musicStream);
m_musicStreamActive = false; m_musicStreamActive = false;
} }
SetIsPlayingStreamingCDMusic(false); SetIsPlayingStreamingCDMusic(false);
SetIsPlayingStreamingGameMusic(false); SetIsPlayingStreamingGameMusic(false);
m_StreamState = eMusicStreamState_Idle; m_StreamState = eMusicStreamState_Idle;
break; break;
case eMusicStreamState_Stopping:
break; case eMusicStreamState_Playing:
case eMusicStreamState_Play:
break;
case eMusicStreamState_Playing: {
static int frameCount = 0;
if (frameCount++ % 60 == 0) {
if (m_musicStreamActive) {
bool isPlaying = ma_sound_is_playing(&m_musicStream);
float vol = ma_sound_get_volume(&m_musicStream);
bool isAtEnd = ma_sound_at_end(&m_musicStream);
}
}
}
if (GetIsPlayingStreamingGameMusic()) { if (GetIsPlayingStreamingGameMusic()) {
{ bool playerInEnd = false, playerInNether = false;
bool playerInEnd = false; Minecraft* pMinecraft = Minecraft::GetInstance();
bool playerInNether = false;
Minecraft* pMinecraft = Minecraft::GetInstance();
for (unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i) {
if (pMinecraft->localplayers[i] != nullptr) {
if (pMinecraft->localplayers[i]->dimension ==
LevelData::DIMENSION_END) {
playerInEnd = true;
} else if (pMinecraft->localplayers[i]->dimension ==
LevelData::DIMENSION_NETHER) {
playerInNether = true;
}
}
}
if (playerInEnd && !GetIsPlayingEndMusic()) { for (unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i) {
m_StreamState = eMusicStreamState_Stop; if (pMinecraft->localplayers[i]) {
if (pMinecraft->localplayers[i]->dimension ==
// Set the end track LevelData::DIMENSION_END)
m_musicID = getMusicID(LevelData::DIMENSION_END); playerInEnd = true;
SetIsPlayingEndMusic(true); else if (pMinecraft->localplayers[i]->dimension ==
SetIsPlayingNetherMusic(false); LevelData::DIMENSION_NETHER)
} else if (!playerInEnd && GetIsPlayingEndMusic()) { playerInNether = true;
if (playerInNether) {
m_StreamState = eMusicStreamState_Stop;
// Set the end track
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
SetIsPlayingEndMusic(false);
SetIsPlayingNetherMusic(true);
} else {
m_StreamState = eMusicStreamState_Stop;
// Set the end track
m_musicID =
getMusicID(LevelData::DIMENSION_OVERWORLD);
SetIsPlayingEndMusic(false);
SetIsPlayingNetherMusic(false);
}
} else if (playerInNether && !GetIsPlayingNetherMusic()) {
m_StreamState = eMusicStreamState_Stop;
// set the Nether track
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
SetIsPlayingNetherMusic(true);
SetIsPlayingEndMusic(false);
} else if (!playerInNether && GetIsPlayingNetherMusic()) {
if (playerInEnd) {
m_StreamState = eMusicStreamState_Stop;
// set the Nether track
m_musicID = getMusicID(LevelData::DIMENSION_END);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(true);
} else {
m_StreamState = eMusicStreamState_Stop;
// set the Nether track
m_musicID =
getMusicID(LevelData::DIMENSION_OVERWORLD);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(false);
}
}
// volume change required?
if (m_musicStreamActive) {
float finalVolume =
m_StreamingAudioInfo.volume * fMusicVol;
ma_sound_set_volume(&m_musicStream, finalVolume);
} }
} }
} else {
// Music disc playing - if it's a 3D stream, then set the
// position - we don't have any streaming audio in the world
// that moves, so this isn't required unless we have more than
// one listener, and are setting the listening position to the
// origin and setting a fake position for the sound down the z
// axis
if (m_StreamingAudioInfo.bIs3D && m_validListenerCount > 1) {
int iClosestListener = 0;
float fClosestDist = 1e6f;
for (size_t i = 0; i < MAX_LOCAL_PLAYERS; i++) { // Handle Dimension Switching
if (m_ListenerA[i].bValid) { bool needsStop = false;
float dx = m_StreamingAudioInfo.x - if (playerInEnd && !GetIsPlayingEndMusic()) {
m_ListenerA[i].vPosition.x; m_musicID = getMusicID(LevelData::DIMENSION_END);
float dy = m_StreamingAudioInfo.y - SetIsPlayingEndMusic(true);
m_ListenerA[i].vPosition.y; SetIsPlayingNetherMusic(false);
float dz = m_StreamingAudioInfo.z - needsStop = true;
m_ListenerA[i].vPosition.z; } else if (!playerInEnd && GetIsPlayingEndMusic()) {
float dist = sqrtf(dx * dx + dy * dy + dz * dz); m_musicID =
playerInNether
? getMusicID(LevelData::DIMENSION_NETHER)
: getMusicID(LevelData::DIMENSION_OVERWORLD);
SetIsPlayingEndMusic(false);
SetIsPlayingNetherMusic(playerInNether);
needsStop = true;
} else if (playerInNether && !GetIsPlayingNetherMusic()) {
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
SetIsPlayingNetherMusic(true);
SetIsPlayingEndMusic(false);
needsStop = true;
} else if (!playerInNether && GetIsPlayingNetherMusic()) {
m_musicID =
playerInEnd
? getMusicID(LevelData::DIMENSION_END)
: getMusicID(LevelData::DIMENSION_OVERWORLD);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(playerInEnd);
needsStop = true;
}
if (dist < fClosestDist) { if (needsStop) m_StreamState = eMusicStreamState_Stop;
fClosestDist = dist;
iClosestListener = i; // volume change required?
} if (m_musicStreamActive)
ma_sound_set_volume(
&m_musicStream,
m_StreamingAudioInfo.volume * fMusicVol);
} else if (m_StreamingAudioInfo.bIs3D && m_validListenerCount > 1 &&
m_musicStreamActive) {
float fClosestDist = 1e6f;
int iClosest = 0;
for (size_t i = 0; i < MAX_LOCAL_PLAYERS; i++) {
if (m_ListenerA[i].bValid) {
float dist = sqrtf(powf(m_StreamingAudioInfo.x -
m_ListenerA[i].vPosition.x,
2) +
powf(m_StreamingAudioInfo.y -
m_ListenerA[i].vPosition.y,
2) +
powf(m_StreamingAudioInfo.z -
m_ListenerA[i].vPosition.z,
2));
if (dist < fClosestDist) {
fClosestDist = dist;
iClosest = i;
} }
} }
float relX = m_StreamingAudioInfo.x -
m_ListenerA[iClosestListener].vPosition.x;
float relY = m_StreamingAudioInfo.y -
m_ListenerA[iClosestListener].vPosition.y;
float relZ = m_StreamingAudioInfo.z -
m_ListenerA[iClosestListener].vPosition.z;
if (m_musicStreamActive) {
ma_sound_set_position(&m_musicStream, relX, relY, relZ);
}
} }
ma_sound_set_position(
&m_musicStream,
m_StreamingAudioInfo.x - m_ListenerA[iClosest].vPosition.x,
m_StreamingAudioInfo.y - m_ListenerA[iClosest].vPosition.y,
m_StreamingAudioInfo.z - m_ListenerA[iClosest].vPosition.z);
} }
break; break;
case eMusicStreamState_Completed: { case eMusicStreamState_Completed:
// random delay of up to 3 minutes for music m_iMusicDelay = random->nextInt(20 * 60 * 3);
m_iMusicDelay = random->nextInt( {
20 * 60 * 3); // random->nextInt(20 * 60 * 10) + 20 * 60 * 10; int dim = LevelData::DIMENSION_OVERWORLD;
// Check if we have a local player in The Nether or in The End, and Minecraft* pMc = Minecraft::GetInstance();
// play that music if they are for (int i = 0; i < MAX_LOCAL_PLAYERS; i++) {
Minecraft* pMinecraft = Minecraft::GetInstance(); if (pMc->localplayers[i]) {
bool playerInEnd = false; dim = pMc->localplayers[i]->dimension;
bool playerInNether = false; break;
for (unsigned int i = 0; i < MAX_LOCAL_PLAYERS; i++) {
if (pMinecraft->localplayers[i] != nullptr) {
if (pMinecraft->localplayers[i]->dimension ==
LevelData::DIMENSION_END) {
playerInEnd = true;
} else if (pMinecraft->localplayers[i]->dimension ==
LevelData::DIMENSION_NETHER) {
playerInNether = true;
} }
} }
m_musicID = getMusicID(dim);
SetIsPlayingEndMusic(dim == LevelData::DIMENSION_END);
SetIsPlayingNetherMusic(dim == LevelData::DIMENSION_NETHER);
} }
if (playerInEnd) {
m_musicID = getMusicID(LevelData::DIMENSION_END);
SetIsPlayingEndMusic(true);
SetIsPlayingNetherMusic(false);
} else if (playerInNether) {
m_musicID = getMusicID(LevelData::DIMENSION_NETHER);
SetIsPlayingNetherMusic(true);
SetIsPlayingEndMusic(false);
} else {
m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(false);
}
m_StreamState = eMusicStreamState_Idle; m_StreamState = eMusicStreamState_Idle;
} break; break;
} }
// check the status of the stream - this is for when a track completes // check the status of the stream - this is for when a track completes
// rather than is stopped by the user action // rather than is stopped by the user action
if (m_musicStreamActive) { if (m_musicStreamActive && !ma_sound_is_playing(&m_musicStream) &&
if (!ma_sound_is_playing(&m_musicStream) && ma_sound_at_end(&m_musicStream)) {
ma_sound_at_end(&m_musicStream)) { ma_sound_uninit(&m_musicStream);
ma_sound_uninit(&m_musicStream); m_musicStreamActive = false;
m_musicStreamActive = false; SetIsPlayingStreamingCDMusic(false);
SetIsPlayingStreamingGameMusic(false);
SetIsPlayingStreamingCDMusic(false); m_StreamState = eMusicStreamState_Completed;
SetIsPlayingStreamingGameMusic(false);
m_StreamState = eMusicStreamState_Completed;
}
} }
} }
@ -2302,7 +2065,8 @@ F32 AILCALLBACK custom_falloff_function(HSAMPLE S, F32 distance,
} }
#endif #endif
// Universal, these functions shouldn't need platform specific implementations // Universal, these functions shouldn't need platform specific
// implementations
void SoundEngine::updateMusicVolume(float fVal) { m_MasterMusicVolume = fVal; } void SoundEngine::updateMusicVolume(float fVal) { m_MasterMusicVolume = fVal; }
void SoundEngine::updateSystemMusicPlaying(bool isPlaying) { void SoundEngine::updateSystemMusicPlaying(bool isPlaying) {
m_bSystemMusicPlaying = isPlaying; m_bSystemMusicPlaying = isPlaying;

View file

@ -51,6 +51,10 @@
#include "../Minecraft.Client/Utils/ArchiveFile.h" #include "../Minecraft.Client/Utils/ArchiveFile.h"
#endif #endif
#include "../Minecraft.Client/Minecraft.h" #include "../Minecraft.Client/Minecraft.h"
#if defined(__linux__)
#include <unistd.h>
#include <climits>
#endif
#ifdef _XBOX #ifdef _XBOX
#include "../Minecraft.Client/Platform/Xbox/GameConfig/Minecraft.spa.h" #include "../Minecraft.Client/Platform/Xbox/GameConfig/Minecraft.spa.h"
#include "../Minecraft.Client/Platform/Xbox/Network/NetworkPlayerXbox.h" #include "../Minecraft.Client/Platform/Xbox/Network/NetworkPlayerXbox.h"
@ -4583,7 +4587,6 @@ int CMinecraftApp::BannedLevelDialogReturned(
return 0; return 0;
} }
void CMinecraftApp::loadMediaArchive() { void CMinecraftApp::loadMediaArchive() {
std::wstring mediapath = L""; std::wstring mediapath = L"";
@ -4602,8 +4605,20 @@ void CMinecraftApp::loadMediaArchive() {
#endif #endif
if (!mediapath.empty()) { if (!mediapath.empty()) {
// boom headshot
#if defined(__linux__)
std::wstring exeDirW = PathHelper::GetExecutableDirW();
std::wstring candidate = exeDirW + File::pathSeparator + mediapath;
if (File(candidate).exists()) {
m_mediaArchive = new ArchiveFile(File(candidate));
} else {
m_mediaArchive = new ArchiveFile(File(mediapath));
}
#else
m_mediaArchive = new ArchiveFile(File(mediapath)); m_mediaArchive = new ArchiveFile(File(mediapath));
#endif
} }
}
#if 0 #if 0
std::string path = "Common\\media.arc"; std::string path = "Common\\media.arc";
HANDLE hFile = CreateFile( path.c_str(), HANDLE hFile = CreateFile( path.c_str(),

View file

@ -1,8 +1,14 @@
#include "../Platform/stdafx.h" #include "../Platform/stdafx.h"
#include "../../Minecraft.World/Util/StringHelpers.h" #include "../../Minecraft.World/Util/StringHelpers.h"
#include "Textures.h" #include "Textures.h"
#include "PathHelper.h"
#include "../../Minecraft.World/Util/ArrayWithLength.h" #include "../../Minecraft.World/Util/ArrayWithLength.h"
#include "BufferedImage.h" #include "BufferedImage.h"
#if defined(__linux__)
#include <unistd.h>
#endif
#include <vector>
#include <string>
#ifdef _XBOX #ifdef _XBOX
typedef struct { typedef struct {
@ -28,7 +34,7 @@ BufferedImage::BufferedImage(int width, int height, int type) {
data[0] = new int[width * height]; data[0] = new int[width * height];
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
data[i] = NULL; data[i] = nullptr;
} }
this->width = width; this->width = width;
this->height = height; this->height = height;
@ -43,186 +49,125 @@ void BufferedImage::ByteFlip4(unsigned int& data) {
// the compression method. Compression method 3 is a 32-bit image with only // the compression method. Compression method 3 is a 32-bit image with only
// 24-bits used (ie no alpha channel) whereas method 0 is a full 32-bit image // 24-bits used (ie no alpha channel) whereas method 0 is a full 32-bit image
// with a valid alpha channel. // with a valid alpha channel.
// 4jcraft: mostly rewrote this function
BufferedImage::BufferedImage(const std::wstring& File, BufferedImage::BufferedImage(const std::wstring& File,
bool filenameHasExtension /*=false*/, bool filenameHasExtension,
bool bTitleUpdateTexture /*=false*/, bool bTitleUpdateTexture,
const std::wstring& drive /*=L""*/) { const std::wstring& drive) {
HRESULT hr; HRESULT hr = -1;
std::wstring wDrive; std::wstring filePath = File;
std::wstring filePath;
filePath = File;
wDrive = drive; for (size_t i = 0; i < filePath.length(); ++i) {
if (wDrive.empty()) { if (filePath[i] == L'\\') filePath[i] = L'/';
#ifdef _XBOX }
if (bTitleUpdateTexture) { for (int l = 0; l < 10; l++) data[l] = nullptr;
// Make the content package point to to the UPDATE: drive is needed
#ifdef _TU_BUILD
wDrive = L"UPDATE:\\";
#else
wDrive = L"GAME:\\res\\TitleUpdate\\"; std::wstring baseName = filePath;
#endif if (!filenameHasExtension) {
} else { if (baseName.size() > 4 &&
wDrive = L"GAME:\\"; baseName.substr(baseName.size() - 4) == L".png") {
baseName = baseName.substr(0, baseName.size() - 4);
} }
#else
#ifdef __PS3__
char* pchUsrDir;
if (app.GetBootedFromDiscPatch()) {
const char* pchTextureName = wstringtofilename(File);
pchUsrDir = app.GetBDUsrDirPath(pchTextureName);
} else {
pchUsrDir = getUsrDirPath();
}
std::wstring wstr(pchUsrDir, pchUsrDir + strlen(pchUsrDir));
if (bTitleUpdateTexture) {
// Make the content package point to to the UPDATE: drive is needed
wDrive = wstr + L"\\Common\\res\\TitleUpdate\\";
} else {
wDrive = wstr + L"/Common/";
}
#elif __PSVITA__
/*char *pchUsrDir=getUsrDirPath();
wstring wstr (pchUsrDir, pchUsrDir+strlen(pchUsrDir));
if(bTitleUpdateTexture)
{
// Make the content package point to to the UPDATE: drive is
needed wDrive= wstr + L"\\Common\\res\\TitleUpdate\\";
}
else
{
wDrive= wstr + L"/Common/";
}*/
if (bTitleUpdateTexture) {
// Make the content package point to to the UPDATE: drive is needed
wDrive = L"Common\\res\\TitleUpdate\\";
} else {
wDrive = L"Common/";
}
#else
if (bTitleUpdateTexture) {
// Make the content package point to to the UPDATE: drive is needed
wDrive = L"Common\\res\\TitleUpdate\\";
} else {
wDrive = L"Common/";
}
#endif
#endif
} }
for (int l = 0; l < 10; l++) { while (!baseName.empty() && (baseName[0] == L'/' || baseName[0] == L'\\'))
data[l] = NULL; baseName = baseName.substr(1);
} if (baseName.find(L"res/") == 0) baseName = baseName.substr(4);
std::wstring exeDir = PathHelper::GetExecutableDirW();
for (int l = 0; l < 10; l++) { for (int l = 0; l < 10; l++) {
std::wstring name; std::wstring mipSuffix =
std::wstring mipMapPath = L""; (l != 0) ? L"MipMapLevel" + _toString<int>(l + 1) : L"";
if (l != 0) { std::wstring fileName = baseName + mipSuffix + L".png";
mipMapPath = L"MipMapLevel" + _toString<int>(l + 1); std::wstring finalPath;
} bool foundOnDisk = false;
if (filenameHasExtension) {
name = wDrive + L"res" + filePath.substr(0, filePath.length());
} else {
name = wDrive + L"res" + filePath.substr(0, filePath.length() - 4) +
mipMapPath + L".png";
}
const char* pchTextureName = wstringtofilename(name); std::vector<std::wstring> searchPaths = {
exeDir + L"/Common/res/TitleUpdate/res/" + fileName,
exeDir + L"/Common/res/" + fileName,
exeDir + L"/Common/Media/Graphics/" + fileName,
exeDir + L"/Common/Media/font/" + fileName,
exeDir + L"/Common/res/font/" + fileName,
exeDir + L"/Common/Media/" + fileName};
#ifndef _CONTENT_PACKAGE for (auto& attempt : searchPaths) {
app.DebugPrintf("\n--- Loading TEXTURE - %s\n\n", pchTextureName); size_t p;
#endif while ((p = attempt.find(L"//")) != std::wstring::npos)
attempt.replace(p, 2, L"/");
if (access(wstringtofilename(attempt), F_OK) != -1) {
finalPath = attempt;
foundOnDisk = true;
break;
}
}
D3DXIMAGE_INFO ImageInfo; D3DXIMAGE_INFO ImageInfo;
ZeroMemory(&ImageInfo, sizeof(D3DXIMAGE_INFO)); ZeroMemory(&ImageInfo, sizeof(D3DXIMAGE_INFO));
hr =
RenderManager.LoadTextureData(pchTextureName, &ImageInfo, &data[l]);
if (hr != ERROR_SUCCESS) { if (foundOnDisk) {
// 4J - If we haven't loaded the non-mipmap version then exit the hr = RenderManager.LoadTextureData(wstringtofilename(finalPath),
// game &ImageInfo, &data[l]);
if (l == 0) { } else {
app.FatalLoadError(); std::wstring archiveKey = L"res/" + fileName;
if (app.hasArchiveFile(archiveKey)) {
byteArray ba = app.getArchiveFile(archiveKey);
hr = RenderManager.LoadTextureData(ba.data, ba.length,
&ImageInfo, &data[l]);
} }
return;
} }
if (l == 0) { if (hr == ERROR_SUCCESS) {
width = ImageInfo.Width; if (l == 0) {
height = ImageInfo.Height; width = ImageInfo.Width;
height = ImageInfo.Height;
}
} else {
if (l == 0) {
// safety dummy to prevent crash
width = 1;
height = 1;
data[0] = new int[1];
data[0][0] = 0xFFFF00FF;
}
break;
} }
} }
} }
BufferedImage::BufferedImage(DLCPack* dlcPack, const std::wstring& File, BufferedImage::BufferedImage(DLCPack* dlcPack, const std::wstring& File,
bool filenameHasExtension /*= false*/) { bool filenameHasExtension) {
HRESULT hr; HRESULT hr;
std::wstring filePath = File; std::wstring filePath = File;
std::uint8_t* pbData = NULL; std::uint8_t* pbData = nullptr;
std::uint32_t dataBytes = 0; std::uint32_t dataBytes = 0;
for (int l = 0; l < 10; l++) data[l] = nullptr;
for (int l = 0; l < 10; l++) {
data[l] = NULL;
}
for (int l = 0; l < 10; l++) { for (int l = 0; l < 10; l++) {
std::wstring name; std::wstring name;
std::wstring mipMapPath = L""; std::wstring mipMapPath =
if (l != 0) { (l != 0) ? L"MipMapLevel" + _toString<int>(l + 1) : L"";
mipMapPath = L"MipMapLevel" + _toString<int>(l + 1); name = L"res" + (filenameHasExtension
} ? filePath
if (filenameHasExtension) { : filePath.substr(0, filePath.length() - 4) +
name = L"res" + filePath.substr(0, filePath.length()); mipMapPath + L".png");
} else {
name = L"res" + filePath.substr(0, filePath.length() - 4) +
mipMapPath + L".png";
}
if (!dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, name)) { if (!dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, name)) {
// 4J - If we haven't loaded the non-mipmap version then exit the if (l == 0) app.FatalLoadError();
// game
if (l == 0) {
app.FatalLoadError();
}
return; return;
} }
DLCFile* dlcFile = dlcPack->getFile(DLCManager::e_DLCType_All, name); DLCFile* dlcFile = dlcPack->getFile(DLCManager::e_DLCType_All, name);
pbData = dlcFile->getData(dataBytes); pbData = dlcFile->getData(dataBytes);
if (pbData == NULL || dataBytes == 0) { if (pbData == nullptr || dataBytes == 0) {
// 4J - If we haven't loaded the non-mipmap version then exit the if (l == 0) app.FatalLoadError();
// game
if (l == 0) {
app.FatalLoadError();
}
return; return;
} }
D3DXIMAGE_INFO ImageInfo; D3DXIMAGE_INFO ImageInfo;
ZeroMemory(&ImageInfo, sizeof(D3DXIMAGE_INFO));
hr = RenderManager.LoadTextureData(pbData, dataBytes, &ImageInfo, hr = RenderManager.LoadTextureData(pbData, dataBytes, &ImageInfo,
&data[l]); &data[l]);
if (hr == ERROR_SUCCESS && l == 0) {
if (hr != ERROR_SUCCESS) {
// 4J - If we haven't loaded the non-mipmap version then exit the
// game
if (l == 0) {
app.FatalLoadError();
}
return;
}
if (l == 0) {
width = ImageInfo.Width; width = ImageInfo.Width;
height = ImageInfo.Height; height = ImageInfo.Height;
} }
@ -230,9 +175,8 @@ BufferedImage::BufferedImage(DLCPack* dlcPack, const std::wstring& File,
} }
BufferedImage::BufferedImage(std::uint8_t* pbData, std::uint32_t dataBytes) { BufferedImage::BufferedImage(std::uint8_t* pbData, std::uint32_t dataBytes) {
int iCurrentByte = 0;
for (int l = 0; l < 10; l++) { for (int l = 0; l < 10; l++) {
data[l] = NULL; data[l] = nullptr;
} }
D3DXIMAGE_INFO ImageInfo; D3DXIMAGE_INFO ImageInfo;
@ -273,7 +217,7 @@ int* BufferedImage::getData() { return data[0]; }
int* BufferedImage::getData(int level) { return data[level]; } int* BufferedImage::getData(int level) { return data[level]; }
Graphics* BufferedImage::getGraphics() { return NULL; } Graphics* BufferedImage::getGraphics() { return nullptr; }
// Returns the transparency. Returns either OPAQUE, BITMASK, or TRANSLUCENT. // Returns the transparency. Returns either OPAQUE, BITMASK, or TRANSLUCENT.
// Specified by: // Specified by:
@ -299,14 +243,15 @@ BufferedImage* BufferedImage::getSubimage(int x, int y, int w, int h) {
this->getRGB(x, y, w, h, arrayWrapper, 0, w); this->getRGB(x, y, w, h, arrayWrapper, 0, w);
int level = 1; int level = 1;
while (getData(level) != NULL) { // prevent overflow
while (level < 10 && getData(level) != nullptr) {
int ww = w >> level; int ww = w >> level;
int hh = h >> level; int hh = h >> level;
int xx = x >> level; int xx = x >> level;
int yy = y >> level; int yy = y >> level;
img->data[level] = new int[ww * hh]; img->data[level] = new int[ww * hh];
intArray arrayWrapper(img->data[level], ww * hh); intArray levelWrapper(img->data[level], ww * hh);
this->getRGB(xx, yy, ww, hh, arrayWrapper, 0, ww, level); this->getRGB(xx, yy, ww, hh, levelWrapper, 0, ww, level);
++level; ++level;
} }
@ -324,7 +269,8 @@ void BufferedImage::preMultiplyAlpha() {
int b = 0; int b = 0;
int total = width * height; int total = width * height;
for (unsigned int i = 0; i < total; ++i) { // why was it unsigned??
for (int i = 0; i < total; ++i) {
cur = curData[i]; cur = curData[i];
alpha = (cur >> 24) & 0xff; alpha = (cur >> 24) & 0xff;
r = ((cur >> 16) & 0xff) * (float)alpha / 255; r = ((cur >> 16) & 0xff) * (float)alpha / 255;

View file

@ -2,7 +2,7 @@
#include "FileFilter.h" #include "FileFilter.h"
#include "../../Level/Storage/McRegionLevelStorageSource.h" #include "../../Level/Storage/McRegionLevelStorageSource.h"
#include "File.h" #include "File.h"
#include "PathHelper.h"
#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) #if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__)
#include <chrono> #include <chrono>
#include <filesystem> #include <filesystem>
@ -57,17 +57,54 @@ File::File(const File& parent, const std::wstring& child) {
// Creates a new File instance by converting the given pathname string into an // Creates a new File instance by converting the given pathname string into an
// abstract pathname. // abstract pathname.
File::File(const std::wstring& pathname) //: parent( NULL )
{ File::File(const std::wstring& pathname) {
// #ifndef _CONTENT_PACKAGE if (pathname.empty()) {
// char buf[256]; m_abstractPathName = L"";
// wcstombs(buf, pathname.c_str(), 256); return;
// printf("File::File - %s\n",buf); }
// #endif
if (pathname.empty()) std::wstring fixedPath = pathname;
m_abstractPathName = std::wstring(L""); for (size_t i = 0; i < fixedPath.length(); ++i) {
else if (fixedPath[i] == L'\\') fixedPath[i] = L'/';
m_abstractPathName = pathname; }
size_t dpos;
while ((dpos = fixedPath.find(L"//")) != std::wstring::npos)
fixedPath.erase(dpos, 1);
if (fixedPath.find(L"GAME:/") == 0) fixedPath = fixedPath.substr(6);
m_abstractPathName = fixedPath;
#if defined(__linux__)
std::string request = wstringtofilename(m_abstractPathName);
while (!request.empty() && request[0] == '/') request.erase(0, 1);
if (request.find("res/") == 0) request.erase(0, 4);
std::string exeDir = PathHelper::GetExecutableDirA();
std::string fileName = request;
size_t lastSlash = fileName.find_last_of('/');
if (lastSlash != std::string::npos)
fileName = fileName.substr(lastSlash + 1);
const char* bases[] = {"/",
"/Common/res/TitleUpdate/res/",
"/Common/Media/",
"/Common/res/",
"/Common/",
"/Minecraft.Assets/"};
for (const char* base : bases) {
std::string tryFull = exeDir + base + request;
std::string tryFile = exeDir + base + fileName;
if (access(tryFull.c_str(), F_OK) != -1) {
m_abstractPathName = convStringToWstring(tryFull);
return;
}
if (access(tryFile.c_str(), F_OK) != -1) {
m_abstractPathName = convStringToWstring(tryFile);
return;
}
}
#endif
#ifdef _WINDOWS64 #ifdef _WINDOWS64
std::string path = wstringtofilename(m_abstractPathName); std::string path = wstringtofilename(m_abstractPathName);

View file

@ -0,0 +1,37 @@
#pragma once
#include <string>
#if defined(__linux__)
#include <unistd.h>
#include <limits.h>
#endif
namespace PathHelper {
inline std::wstring GetExecutableDirW() {
#if defined(__linux__)
char buffer[4096];
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len != -1) {
buffer[len] = '\0';
std::string path(buffer);
size_t lastSlash = path.find_last_of('/');
if (lastSlash != std::string::npos)
return std::wstring(path.begin(), path.begin() + lastSlash);
}
#endif
return L".";
}
inline std::string GetExecutableDirA() {
#if defined(__linux__)
char buffer[4096];
ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
if (len != -1) {
buffer[len] = '\0';
std::string path(buffer);
size_t lastSlash = path.find_last_of('/');
if (lastSlash != std::string::npos) return path.substr(0, lastSlash);
}
#endif
return ".";
}
} // namespace PathHelper