Merge pull request 'TU31 final blocks + changes' (#9) from Fireblade/neoLegacy:TU31 into main

Reviewed-on: https://git.neolegacy.dev/neoStudiosLCE/neoLegacy/pulls/9
This commit is contained in:
Fireblade
2026-07-05 23:34:03 +01:00
632 changed files with 39424 additions and 31829 deletions
+38
View File
@@ -0,0 +1,38 @@
{
"tasks": [
{
"label": "Build Release [Linux]",
"type": "shell",
"command": "bash",
"args": [
"-c",
"./build-linux.sh . Release && ${env:HOME}/.local/share/neoLegacy/minecraft-lce-client"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Builds + runs the project in Release mode w/ build-linux.sh"
},
{
"label": "Build Debug [Linux]",
"type": "shell",
"command": "bash",
"args": [
"-c",
"./build-linux.sh . Debug && ${env:HOME}/.local/share/neoLegacy/minecraft-lce-client"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [],
"group": "build",
"detail": "Builds + runs the project in Debug mode w/ build-linux.sh"
}
],
"version": "2.0.0"
}
+3
View File
@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.24)
cmake_policy(SET CMP0057 NEW)
project(LCE-Revelations LANGUAGES C CXX RC ASM_MASM)
set(CMAKE_CXX_STANDARD 17)
@@ -234,6 +235,8 @@ if(TARGET Minecraft.Server)
add_dependencies(Minecraft.Server GenerateStringIdLookup)
endif()
# item.h takes priority as some tile.h blocks are not meant to be accessed
# for example: the wheat 'block' (stage 1 wheat crop) is NOT supposed to override the normal wheat item
set(_item_map_inputs
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Item.h"
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/Tile.h"
+114 -3
View File
@@ -35,6 +35,107 @@ wstring AbstractTexturePack::trim(wstring line)
return line;
}
namespace {
class XmlColourTableCallback : public ATG::ISAXCallback
{
public:
HRESULT StartDocument() override { return S_OK; }
HRESULT EndDocument() override { return S_OK; }
HRESULT ElementBegin(CONST WCHAR *strName, UINT NameLen, CONST ATG::XMLAttribute *pAttributes, UINT NumAttributes) override
{
const wstring elementName(strName, NameLen);
if (!equalsIgnoreCase(elementName, L"colour"))
{
return S_OK;
}
wstring colourName;
wstring colourValueText;
for(UINT i = 0; i < NumAttributes; ++i)
{
const ATG::XMLAttribute &attribute = pAttributes[i];
if (attribute.strValue == nullptr)
{
continue;
}
const wstring attributeName(attribute.strName, attribute.NameLen);
if (equalsIgnoreCase(attributeName, L"name"))
{
colourName.assign(attribute.strValue, attribute.ValueLen);
}
else if (equalsIgnoreCase(attributeName, L"value"))
{
colourValueText.assign(attribute.strValue, attribute.ValueLen);
}
}
if (!colourName.empty() && !colourValueText.empty())
{
if (colourValueText[0] == L'#')
{
colourValueText = colourValueText.substr(1);
}
int colourValue = _fromHEXString<int>(colourValueText);
m_colours.emplace_back(colourName, colourValue);
}
return S_OK;
}
HRESULT ElementContent(CONST WCHAR *, UINT, BOOL) override { return S_OK; }
HRESULT ElementEnd(CONST WCHAR *, UINT) override { return S_OK; }
HRESULT CDATABegin() override { return S_OK; }
HRESULT CDATAData(CONST WCHAR *, UINT, BOOL) override { return S_OK; }
HRESULT CDATAEnd() override { return S_OK; }
VOID Error(HRESULT hError, CONST CHAR *strMessage) override
{
app.DebugPrintf("colours.xml parse error (%08X): %s\n", hError, strMessage ? strMessage : "(unknown)");
}
vector<pair<wstring,int>> m_colours;
};
static bool loadColourTableFromXmlFile(File xmlFile, ColourTable *&outTable)
{
FileInputStream fis(xmlFile);
DWORD dwLength = xmlFile.length();
if(dwLength == 0) return false;
byteArray textData(static_cast<unsigned int>(dwLength));
fis.read(textData, 0, dwLength);
fis.close();
ATG::XMLParser parser;
XmlColourTableCallback callback;
parser.RegisterSAXCallbackInterface(&callback);
HRESULT hr = parser.ParseXMLBuffer(reinterpret_cast<const CHAR *>(textData.data), static_cast<UINT>(dwLength));
delete [] textData.data;
if (FAILED(hr) || callback.m_colours.empty())
return false;
ByteArrayOutputStream baos;
DataOutputStream dos(&baos);
dos.writeInt(1);
dos.writeInt(static_cast<int>(callback.m_colours.size()));
for (const auto &entry : callback.m_colours)
{
dos.writeUTF(entry.first);
dos.writeInt(entry.second);
}
byteArray binaryData = baos.toByteArray();
outTable = new ColourTable(binaryData.data, binaryData.length);
delete [] binaryData.data;
return true;
}
}
void AbstractTexturePack::loadIcon()
{
#ifdef _XBOX
@@ -223,7 +324,7 @@ wstring AbstractTexturePack::getAnimationString(const wstring &textureName, cons
BufferedImage *AbstractTexturePack::getImageResource(const wstring& File, bool filenameHasExtension /*= false*/, bool bTitleUpdateTexture /*=false*/, const wstring &drive /*=L""*/)
{
const char *pchTexture=wstringtofilename(File);
app.DebugPrintf("AbstractTexturePack::getImageResource - %s, drive is %s\n",pchTexture, wstringtofilename(drive));
// app.DebugPrintf("AbstractTexturePack::getImageResource - %s, drive is %s\n",pchTexture, wstringtofilename(drive));
return new BufferedImage(TexturePack::getResource(L"/" + File),filenameHasExtension,bTitleUpdateTexture,drive);
}
@@ -261,12 +362,12 @@ void AbstractTexturePack::loadDefaultColourTable()
#ifdef __PS3__
// need to check if it's a BD build, so pass in the name
File coloursFile(AbstractTexturePack::getPath(true,app.GetBootedFromDiscPatch()?"colours.col":nullptr).append(L"res/colours.col"));
File coloursXmlFile(AbstractTexturePack::getPath(true,app.GetBootedFromDiscPatch()?"colours.xml":nullptr).append(L"res/colours.xml"));
#else
File coloursFile(AbstractTexturePack::getPath(true).append(L"res/colours.col"));
File coloursXmlFile(AbstractTexturePack::getPath(true).append(L"res/colours.xml"));
#endif
if(coloursFile.exists())
{
DWORD dwLength = coloursFile.length();
@@ -280,6 +381,16 @@ void AbstractTexturePack::loadDefaultColourTable()
delete [] data.data;
}
else if(coloursXmlFile.exists())
{
app.DebugPrintf("Default colours table not found, loading colours.xml fallback\n");
if(m_colourTable != nullptr) delete m_colourTable;
if(!loadColourTableFromXmlFile(coloursXmlFile, m_colourTable))
{
app.DebugPrintf("Failed to load colours.xml as a fallback\n");
app.FatalLoadError();
}
}
else
{
app.DebugPrintf("Failed to load the default colours table\n");
+28 -1
View File
@@ -4,6 +4,7 @@
#include "../Minecraft.World/compression.h"
#include "ArchiveFile.h"
#include "lce_filesystem/FolderFile.h"
void ArchiveFile::_readHeader(DataInputStream *dis)
{
@@ -28,10 +29,19 @@ void ArchiveFile::_readHeader(DataInputStream *dis)
}
}
ArchiveFile::ArchiveFile(File file)
ArchiveFile::ArchiveFile(File file, bool allowFolder)
{
m_cachedData = nullptr;
m_folderFile = nullptr;
m_useFolder = false;
m_sourcefile = file;
if(allowFolder && file.exists() && file.isDirectory())
{
m_folderFile = new FolderFile(file.getPath());
m_useFolder = true;
return;
}
app.DebugPrintf("Loading archive file...\n");
#ifndef _CONTENT_PACKAGE
char buf[256];
@@ -72,10 +82,15 @@ ArchiveFile::ArchiveFile(File file)
ArchiveFile::~ArchiveFile()
{
delete m_cachedData;
delete m_folderFile;
}
vector<wstring> *ArchiveFile::getFileList()
{
if(m_useFolder)
{
return m_folderFile->getFileList();
}
vector<wstring> *out = new vector<wstring>();
for ( const auto& it : m_index )
@@ -86,16 +101,28 @@ vector<wstring> *ArchiveFile::getFileList()
bool ArchiveFile::hasFile(const wstring &filename)
{
if(m_useFolder)
{
return m_folderFile->hasFile(filename);
}
return m_index.find(filename) != m_index.end();
}
int ArchiveFile::getFileSize(const wstring &filename)
{
if(m_useFolder)
{
return m_folderFile->getFileSize(filename);
}
return hasFile(filename) ? m_index.at(filename)->filesize : -1;
}
byteArray ArchiveFile::getFile(const wstring &filename)
{
if(m_useFolder)
{
return m_folderFile->getFile(filename);
}
byteArray out;
auto it = m_index.find(filename);
+5 -1
View File
@@ -8,11 +8,15 @@
using namespace std;
class FolderFile;
class ArchiveFile
{
protected:
File m_sourcefile;
BYTE *m_cachedData;
FolderFile *m_folderFile;
bool m_useFolder;
typedef struct _MetaData
{
@@ -28,7 +32,7 @@ protected:
public:
void _readHeader(DataInputStream *dis);
ArchiveFile(File file);
ArchiveFile(File file, bool allowFolder = false);
~ArchiveFile();
vector<wstring> *getFileList();
+3 -3
View File
@@ -88,7 +88,7 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
segments.push_back({curR, curG, curB, 1});
}
else if (tileID == 0 || tileID == Tile::glass_Id || tileID == Tile::thinGlass_Id) {
else if (tileID == 0 || tileID == Tile::glass_Id || tileID == Tile::glass_pane_Id) {
if (segments.empty()) {
segments.push_back({1.0f, 1.0f, 1.0f, 1});
} else {
@@ -113,7 +113,7 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(true);
double currentYBase = 0;
double currentYBase = 1;
for (const auto& seg : segments) {
int r = (int)(seg.r * 255);
int g = (int)(seg.g * 255);
@@ -163,7 +163,7 @@ void BeaconRenderer::render(shared_ptr<TileEntity> _beacon, double x, double y,
glDepthMask(false);
currentYBase = 0;
currentYBase = 1;
for (const auto& seg : segments) {
int r = (int)(seg.r * 255);
int g = (int)(seg.g * 255);
+22 -4
View File
@@ -163,7 +163,7 @@ BufferedImage::BufferedImage(const wstring& File, bool filenameHasExtension /*=f
const char *pchTextureName=wstringtofilename(name);
#ifndef _CONTENT_PACKAGE
app.DebugPrintf("\n--- Loading TEXTURE - %s\n\n",pchTextureName);
// app.DebugPrintf("\n--- Loading TEXTURE - %s\n\n",pchTextureName);
#endif
D3DXIMAGE_INFO ImageInfo;
@@ -209,16 +209,34 @@ BufferedImage::BufferedImage(DLCPack *dlcPack, const wstring& File, bool filenam
{
mipMapPath = L"MipMapLevel" + std::to_wstring(l+1);
}
wstring basePath;
if( filenameHasExtension )
{
name = L"res" + filePath.substr(0,filePath.length());
basePath = filePath;
}
else
{
name = L"res" + filePath.substr(0,filePath.length()-4) + mipMapPath + L".png";
basePath = filePath.substr(0,filePath.length()-4) + mipMapPath + L".png";
}
if(!dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, name))
wstring candidates[2] =
{
L"res" + basePath,
L"x16Data/res" + basePath
};
bool found = false;
for (const auto &candidate : candidates)
{
if (dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, candidate))
{
name = candidate;
found = true;
break;
}
}
if(!found)
{
// 4J - If we haven't loaded the non-mipmap version then exit the game
if( l == 0 )
+12
View File
@@ -148,6 +148,18 @@ endif()
# Copy redist files
add_copyredist_target(Minecraft.Client)
# replace col file with xml file
add_custom_target(AssetTitleUpdateColourOverride_Minecraft.Client ALL
COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_FILE_DIR:Minecraft.Client>/Common/res/TitleUpdate/res/colours.col"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res/TitleUpdate/res/colours.xml"
"$<TARGET_FILE_DIR:Minecraft.Client>/Common/res/TitleUpdate/res/colours.xml"
VERBATIM
)
add_dependencies(AssetTitleUpdateColourOverride_Minecraft.Client AssetFolderCopy_Minecraft.Client)
add_dependencies(Minecraft.Client AssetTitleUpdateColourOverride_Minecraft.Client)
set_property(TARGET AssetTitleUpdateColourOverride_Minecraft.Client PROPERTY FOLDER "Build")
# Make sure GameHDD exists on Windows
if(PLATFORM_NAME STREQUAL "Windows64")
add_gamehdd_target(Minecraft.Client)
+3 -1
View File
@@ -111,7 +111,9 @@ int Camera::getBlockAt(Level *level, shared_ptr<LivingEntity> player, float alph
Vec3 *p = Camera::getCameraPos(player, alpha);
TilePos tp = TilePos(p);
int t = level->getTile(tp.x, tp.y, tp.z);
if (t != 0 && Tile::tiles[t]->material->isLiquid())
Tile *tile = Tile::tiles[t];
if (tile == nullptr) return 0; // tu31 tutorial world fix
if (t != 0 && tile->material->isLiquid())
{
float hh = LiquidTile::getHeight(level->getData(tp.x, tp.y, tp.z)) - 1 / 9.0f;
float h = tp.y + 1 - hh;
+37 -13
View File
@@ -181,6 +181,7 @@ void Chunk::makeCopyForRebuild(Chunk *source)
void Chunk::rebuild()
{
if (this == nullptr) return;
PIXBeginNamedEvent(0,"Rebuilding chunk %d, %d, %d", x, y, z);
#if defined __PS3__ && !defined DISABLE_SPU_CODE
rebuild_SPU();
@@ -281,15 +282,15 @@ void Chunk::rebuild()
// Establish whether this tile and its neighbours are all made of rock, dirt, unbreakable tiles, or have already
// been determined to meet this criteria themselves and have a tile of 255 set.
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
tileId = tileIds[ offset + ( ( ( xx - 1 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 )) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
tileId = tileIds[ offset + ( ( ( xx + 1 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 )) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
tileId = tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz - 1 ) << 7 ) | ( indexY + 0 )) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
tileId = tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 1 ) << 7 ) | ( indexY + 0 )) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
// Treat the bottom of the world differently - we shouldn't ever be able to look up at this, so consider tiles as invisible
// if they are surrounded on sides other than the bottom
if( yy > 0 )
@@ -302,7 +303,7 @@ void Chunk::rebuild()
yMinusOneOffset = Level::COMPRESSED_CHUNK_SECTION_TILES;
}
tileId = tileIds[ yMinusOneOffset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | indexYMinusOne ) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
}
int indexYPlusOne = yy + 1;
int yPlusOneOffset = 0;
@@ -312,7 +313,7 @@ void Chunk::rebuild()
yPlusOneOffset = Level::COMPRESSED_CHUNK_SECTION_TILES;
}
tileId = tileIds[ yPlusOneOffset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | indexYPlusOne ) ];
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue;
if( !( ( tileId == Tile::stone_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::bedrock_Id ) || ( tileId == 255) ) ) continue;
// This tile is surrounded. Flag it as not requiring to be rendered by setting its id to 255.
tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 ) ) ] = 0xff;
@@ -324,12 +325,14 @@ void Chunk::rebuild()
if( empty )
{
// 4J - added - clear any renderer data associated with this
for (int currentLayer = 0; currentLayer < 2; currentLayer++)
for (int currentLayer = 0; currentLayer < LevelRenderer::CHUNK_RENDER_LAYERS; currentLayer++)
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
if (currentLayer < 2)
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer);
}
RenderManager.CBuffClear(lists + currentLayer);
}
RenderManager.CBuffClear(lists + 2);
delete region;
delete tileRenderer;
@@ -404,6 +407,10 @@ void Chunk::rebuild()
}
Tile *tile = Tile::tiles[tileId];
if (tile == nullptr)
{
continue;
}
if (currentLayer == 0 && tile->isEntityTile())
{
shared_ptr<TileEntity> et = region->getTileEntity(x, y, z);
@@ -416,6 +423,10 @@ void Chunk::rebuild()
if (renderLayer > currentLayer)
{
if (currentLayer == 1 && tile == Tile::slimeBlock)
{
rendered |= tileRenderer->tesselateSlimeInnerInWorld(tile, x, y, z);
}
renderNextLayer = true;
}
else if (renderLayer == currentLayer)
@@ -474,13 +485,26 @@ void Chunk::rebuild()
if((currentLayer==0)&&(!renderNextLayer))
{
levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1);
RenderManager.CBuffClear(lists + 1);
RenderManager.CBuffClear(lists + 2);
for (int clearLayer = 1; clearLayer < LevelRenderer::CHUNK_RENDER_LAYERS; clearLayer++)
{
RenderManager.CBuffClear(lists + clearLayer);
}
break;
}
if((currentLayer==1)&&(!renderNextLayer))
{
RenderManager.CBuffClear(lists + 2);
for (int clearLayer = 2; clearLayer < LevelRenderer::CHUNK_RENDER_LAYERS; clearLayer++)
{
RenderManager.CBuffClear(lists + clearLayer);
}
break;
}
if((currentLayer==2)&&(!renderNextLayer))
{
for (int clearLayer = 3; clearLayer < LevelRenderer::CHUNK_RENDER_LAYERS; clearLayer++)
{
RenderManager.CBuffClear(lists + clearLayer);
}
break;
}
}
+28 -10
View File
@@ -574,7 +574,20 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
int iz = (int) z;
app.DebugPrintf("ClientConnection ITEM_FRAME xyz %d,%d,%d\n",ix,iy,iz);
}
e = std::make_shared<ItemFrame>(level, (int)x, (int)y, (int)z, packet->data);
{
int dir = packet->data & 0xFF;
bool placedByPlayer = (packet->data & 0x100) != 0;
e = std::make_shared<ItemFrame>(level, (int)x, (int)y, (int)z, dir);
shared_ptr<ItemFrame> frame = dynamic_pointer_cast<ItemFrame>(e);
if (frame != nullptr)
{
frame->placedByPlayer = placedByPlayer;
if (placedByPlayer)
{
frame->setDir(dir);
}
}
}
packet->data = 0;
setRot = false;
break;
@@ -706,7 +719,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
if (packet->type == AddEntityPacket::ENDER_CRYSTAL) e = shared_ptr<Entity>( new EnderCrystal(level, x, y, z) );
if (packet->type == AddEntityPacket::FALLING_SAND) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::sand->id) );
if (packet->type == AddEntityPacket::FALLING_GRAVEL) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::gravel->id) );
if (packet->type == AddEntityPacket::FALLING_EGG) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::dragonEgg_Id) );
if (packet->type == AddEntityPacket::FALLING_EGG) e = shared_ptr<Entity>( new FallingTile(level, x, y, z, Tile::dragon_egg_Id) );
*/
@@ -828,6 +841,11 @@ void ClientConnection::handleAddGlobalEntity(shared_ptr<AddGlobalEntityPacket> p
void ClientConnection::handleAddPainting(shared_ptr<AddPaintingPacket> packet)
{
shared_ptr<Painting> painting = std::make_shared<Painting>(level, packet->x, packet->y, packet->z, packet->dir, packet->motive);
painting->placedByPlayer = packet->placedByPlayer;
if (packet->placedByPlayer)
{
painting->setDir(packet->dir);
}
level->putEntity(packet->id, painting);
m_trackedEntityIds.insert(packet->id);
}
@@ -1337,11 +1355,11 @@ void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket>
// Don't bother setting this to dirty if it isn't going to visually change - we get a lot of
// water changing from static to dynamic for instance
if(!( ( ( prevTile == Tile::water_Id ) && ( tile == Tile::calmWater_Id ) ) ||
( ( prevTile == Tile::calmWater_Id ) && ( tile == Tile::water_Id ) ) ||
( ( prevTile == Tile::lava_Id ) && ( tile == Tile::calmLava_Id ) ) ||
( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::calmLava_Id ) ) ||
( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::lava_Id ) ) ) )
if(!( ( ( prevTile == Tile::flowing_water_Id ) && ( tile == Tile::water_Id ) ) ||
( ( prevTile == Tile::water_Id ) && ( tile == Tile::flowing_water_Id ) ) ||
( ( prevTile == Tile::flowing_lava_Id ) && ( tile == Tile::lava_Id ) ) ||
( ( prevTile == Tile::lava_Id ) && ( tile == Tile::lava_Id ) ) ||
( ( prevTile == Tile::lava_Id ) && ( tile == Tile::flowing_lava_Id ) ) ) )
{
dimensionLevel->setTilesDirty(x + xo, y, z + zo, x + xo, y, z + zo);
}
@@ -3160,10 +3178,10 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
break;
case ContainerOpenPacket::BREWING_STAND:
{
shared_ptr<BrewingStandTileEntity> brewingStand = std::make_shared<BrewingStandTileEntity>();
if (packet->customName) brewingStand->setCustomName(packet->title);
shared_ptr<BrewingStandTileEntity> brewing_stand = std::make_shared<BrewingStandTileEntity>();
if (packet->customName) brewing_stand->setCustomName(packet->title);
if( player->openBrewingStand(brewingStand))
if( player->openBrewingStand(brewing_stand))
{
player->containerMenu->containerId = packet->containerId;
}
+9 -5
View File
@@ -23,8 +23,12 @@ ClockTexture::ClockTexture(int iPad, ClockTexture *dataTexture) : StitchedTextur
void ClockTexture::cycleFrames()
{
Minecraft *mc = Minecraft::GetInstance();
int frameCount = getFrames();
if (frameCount <= 0)
{
return;
}
double rott = 0;
if (m_iPad >= 0 && m_iPad < XUSER_MAX_COUNT && mc->level != nullptr && mc->localplayers[m_iPad] != nullptr)
@@ -57,10 +61,10 @@ void ClockTexture::cycleFrames()
// 4J Stu - We share data with another texture
if(m_dataTexture != nullptr)
{
int newFrame = static_cast<int>((rot + 1.0) * m_dataTexture->frames->size()) % m_dataTexture->frames->size();
int newFrame = static_cast<int>((rot + 1.0) * frameCount) % frameCount;
while (newFrame < 0)
{
newFrame = (newFrame + m_dataTexture->frames->size()) % m_dataTexture->frames->size();
newFrame = (newFrame + frameCount) % frameCount;
}
if (newFrame != frame)
{
@@ -70,10 +74,10 @@ void ClockTexture::cycleFrames()
}
else
{
int newFrame = static_cast<int>((rot + 1.0) * frames->size()) % frames->size();
int newFrame = static_cast<int>((rot + 1.0) * frameCount) % frameCount;
while (newFrame < 0)
{
newFrame = (newFrame + frames->size()) % frames->size();
newFrame = (newFrame + frameCount) % frameCount;
}
if (newFrame != frame)
{
+5 -1
View File
@@ -108,7 +108,11 @@ enum EGameHostOptionWorldSize
#define GAMESETTING_VSYNC 0x01000000
#define GAMESETTING_EXCLUSIVEFULLSCREEN 0x02000000
#define GAMESETTING_CLASSICCRAFTING 0x04000000
#define GAMESETTING_HIDESAVESIZEBAR 0x08000000
#define GAMESETTING_CAVESOUNDS 0x08000000
#define GAMESETTING_MINECARTSOUNDS 0x10000000
#define GAMESETTING_HIDESAVESIZEBAR 0x20000000
#define GAMESETTING_SAFECAM 0x40000000
#define GAMESETTING_SWAP 0x80000000
// defines for languages
File diff suppressed because it is too large Load Diff
+1
View File
@@ -85,6 +85,7 @@ typedef struct
// 0x00000200 - eGameSetting_CustomSkinAnim - on
// TU9 // 0x00000400 - eGameSetting_DeathMessages - on
// 0x00070000 - eGameSetting_ControlType - 0..6
// Adding another bitmask to store "special" completion tasks for the tutorial
unsigned int uiSpecialTutorialBitmask;
+192 -64
View File
@@ -29,6 +29,8 @@
#include <mutex>
#include <lce_filesystem/lce_filesystem.h>
constexpr float MUSIC_FADE_DURATION_SECONDS = 4.0f;
#ifdef __ORBIS__
#include <audioout.h>
//#define __DISABLE_MILES__ // MGH disabled for now as it crashes if we call sceNpMatching2Initialize
@@ -448,6 +450,9 @@ SoundEngine::SoundEngine()
m_StreamingAudioInfo.z=0;
m_StreamingAudioInfo.volume=1;
m_StreamingAudioInfo.pitch=1;
m_musicFadeSecondsRemaining = 0.0f;
m_musicFadeLastUpdateTime = std::chrono::steady_clock::now();
m_bCurrentStreamIsCustom = false;
memset(CurrentSoundsPlaying,0,sizeof(int)*(eSoundType_MAX+eSFX_MAX));
memset(m_ListenerA,0,sizeof(AUDIO_LISTENER)*XUSER_MAX_COUNT);
@@ -605,34 +610,8 @@ void SoundEngine::play(int iSound, float x, float y, float z, float volume, floa
m_activeSounds.push_back(s);
}
/////////////////////////////////////////////
//
//
// startElytraSound / stopElytraSound
// Manages a single persistent looping sound for elytra gliding.
// Call startElytraSound every tick while gliding (it no-ops if already running,
// just updates volume). Call stopElytraSound when gliding ends.
//
// IMPORTANT: m_elytraLoopingSound is NOT added to m_activeSounds.
// The tick() cleanup loop deletes sounds where is_playing()==false.
// A looping sound briefly reports is_playing()==false at the loop point,
// which would cause tick() to free it and leave m_elytraLoopingSound dangling.
//
/////////////////////////////////////////////
void SoundEngine::startElytraSound(float x, float y, float z, float volume, float pitch)
MiniAudioSound* SoundEngine::startLoopingSound(const wstring& name, float x, float y, float z, float volume, float pitch, bool bIs3D)
{
// If already initialized just update volume and pitch - never reinitialize mid-flight.
if (m_elytraLoopingSound != nullptr)
{
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&m_elytraLoopingSound->sound, finalVolume);
ma_sound_set_pitch(&m_elytraLoopingSound->sound, pitch);
return;
}
// Resolve file path using the same logic as play().
wstring name = wchSoundNames[eSoundType_ITEM_ELYTRA_FLYING];
char* soundName = ConvertSoundPathToName(name);
char basePath[256];
sprintf_s(basePath, "Windows64Media/Sound/Minecraft/%s", soundName);
@@ -652,42 +631,100 @@ void SoundEngine::startElytraSound(float x, float y, float z, float volume, floa
break;
}
}
if (!found) return;
if (!found)
{
return nullptr;
}
MiniAudioSound* s = new MiniAudioSound();
memset(&s->info, 0, sizeof(AUDIO_INFO));
s->info.volume = volume; s->info.pitch = pitch;
s->info.bIs3D = false;
s->info.iSound = eSoundType_ITEM_ELYTRA_FLYING + eSFX_MAX;
s->info.x = x;
s->info.y = y;
s->info.z = z;
s->info.volume = volume;
s->info.pitch = pitch;
s->info.bIs3D = bIs3D;
s->info.bUseSoundsPitchVal = false;
// Synchronous load so the sound is immediately ready - no ASYNC gap.
if (ma_sound_init_from_file(&m_engine, finalPath, 0,
nullptr, nullptr, &s->sound) != MA_SUCCESS)
if (ma_sound_init_from_file(&m_engine, finalPath, 0, nullptr, nullptr, &s->sound) != MA_SUCCESS)
{
delete s;
return;
return nullptr;
}
ma_sound_set_spatialization_enabled(&s->sound, MA_FALSE);
ma_sound_set_spatialization_enabled(&s->sound, bIs3D ? MA_TRUE : MA_FALSE);
ma_sound_set_looping(&s->sound, MA_TRUE);
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN) finalVolume = SFX_MAX_GAIN;
if (finalVolume > SFX_MAX_GAIN)
finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&s->sound, finalVolume);
ma_sound_set_pitch(&s->sound, pitch);
if (bIs3D)
{
ma_sound_set_position(&s->sound, x, y, z);
}
ma_sound_start(&s->sound);
return s;
}
void SoundEngine::updateLoopingSound(MiniAudioSound* sound, float x, float y, float z, float volume, float pitch)
{
if (sound == nullptr)
{
return;
}
float finalVolume = volume * m_MasterEffectsVolume * SFX_VOLUME_MULTIPLIER;
if (finalVolume > SFX_MAX_GAIN)
finalVolume = SFX_MAX_GAIN;
ma_sound_set_volume(&sound->sound, finalVolume);
ma_sound_set_pitch(&sound->sound, pitch);
ma_sound_set_position(&sound->sound, x, y, z);
}
void SoundEngine::stopLoopingSound(MiniAudioSound* sound)
{
if (sound == nullptr)
{
return;
}
ma_sound_stop(&sound->sound);
ma_sound_uninit(&sound->sound);
delete sound;
}
/////////////////////////////////////////////
//
//
// startElytraSound / stopElytraSound
// Manages a single persistent looping sound for elytra gliding.
// Call startElytraSound every tick while gliding (it no-ops if already running,
// just updates volume). Call stopElytraSound when gliding ends.
//
// IMPORTANT: m_elytraLoopingSound is NOT added to m_activeSounds.
// The tick() cleanup loop deletes sounds where is_playing()==false.
// A looping sound briefly reports is_playing()==false at the loop point,
// which would cause tick() to free it and leave m_elytraLoopingSound dangling.
//
/////////////////////////////////////////////
void SoundEngine::startElytraSound(float x, float y, float z, float volume, float pitch)
{
// If already initialized just update volume and pitch - never reinitialize mid-flight.
if (m_elytraLoopingSound != nullptr)
{
updateLoopingSound(m_elytraLoopingSound, x, y, z, volume, pitch);
return;
}
// NOT added to m_activeSounds - tick() cleanup would delete it at loop boundaries.
m_elytraLoopingSound = s;
m_elytraLoopingSound = startLoopingSound(wchSoundNames[eSoundType_ITEM_ELYTRA_FLYING], x, y, z, volume, pitch, false);
}
void SoundEngine::stopElytraSound()
{
if (m_elytraLoopingSound == nullptr) return;
ma_sound_stop(&m_elytraLoopingSound->sound);
ma_sound_uninit(&m_elytraLoopingSound->sound);
delete m_elytraLoopingSound;
stopLoopingSound(m_elytraLoopingSound);
m_elytraLoopingSound = nullptr;
}
/////////////////////////////////////////////
@@ -793,10 +830,22 @@ void SoundEngine::playStreaming(const wstring& name, float x, float y, float z,
m_StreamingAudioInfo.volume = volume;
m_StreamingAudioInfo.pitch = pitch;
bool bNextCustom = isCustomMusicRequest(name);
bool bCurrentCustom = m_musicStreamActive && m_bCurrentStreamIsCustom;
if(m_StreamState == eMusicStreamState_Playing)
m_StreamState = eMusicStreamState_Stop;
{
if (bCurrentCustom != bNextCustom)
{
m_StreamState = eMusicStreamState_Fading;
m_musicFadeSecondsRemaining = MUSIC_FADE_DURATION_SECONDS;
m_musicFadeLastUpdateTime = std::chrono::steady_clock::now();
}
}
else if(m_StreamState == eMusicStreamState_Opening)
{
m_StreamState = eMusicStreamState_OpeningCancel;
}
if(name.empty())
{
@@ -832,62 +881,79 @@ void SoundEngine::playStreaming(const wstring& name, float x, float y, float z,
else if(playerInNether)
m_musicID = getMusicID(eMusicType_Nether);
else
getGameModeMusicID(pMinecraft, i);
{
bool foundCreative = false;
for(unsigned int j = 0; j < MAX_LOCAL_PLAYERS; j++)
{
if(pMinecraft->localplayers[j] != nullptr &&
pMinecraft->localplayers[j]->abilities.instabuild &&
pMinecraft->localplayers[j]->abilities.mayfly)
{
m_musicID = getMusicID(eMusicType_Creative);
foundCreative = true;
break;
}
}
if(!foundCreative)
{
m_musicID = getMusicID(eMusicType_Overworld);
}
}
}
else
{
// jukebox
m_StreamingAudioInfo.bIs3D=true;
m_musicID=getMusicID(name);
m_iMusicDelay=0;
m_StreamingAudioInfo.bIs3D=true;
m_musicID=getMusicID(name);
m_iMusicDelay=0;
}
}
bool SoundEngine::isCustomMusicRequest(const wstring& name) const
{
if (!name.empty())
{
return false;
}
Minecraft *pMinecraft = Minecraft::GetInstance();
if (!pMinecraft)
{
return false;
}
return pMinecraft->skins->getSelected()->hasAudio();
}
int SoundEngine::GetRandomishTrack(int iStart,int iEnd)
{
// 4J-PB - make it more likely that we'll get a track we've not heard for a while, although repeating tracks sometimes is fine
// if all tracks have been heard, clear the flags
bool bAllTracksHeard=true;
int iVal=iStart;
for(size_t i=iStart;i<=iEnd;i++)
{
if(m_bHeardTrackA[i]==false)
if(m_bHeardTrackA[i]==false)
{
bAllTracksHeard=false;
//app.DebugPrintf("Not heard all tracks yet\n");
break;
}
}
if(bAllTracksHeard)
{
//app.DebugPrintf("Heard all tracks - resetting the tracking array\n");
for(size_t i=iStart;i<=iEnd;i++)
{
m_bHeardTrackA[i]=false;
}
}
// trying to get a track we haven't heard, but not too hard
for(size_t i=0;i<=((iEnd-iStart)/2);i++)
{
// random->nextInt(1) will always return 0
iVal=random->nextInt((iEnd-iStart)+1)+iStart;
if(m_bHeardTrackA[iVal]==false)
{
// not heard this
//app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal);
m_bHeardTrackA[iVal]=true;
break;
}
else
{
//app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal);
}
}
//app.DebugPrintf("Select track %d\n",iVal);
@@ -1331,7 +1397,38 @@ void SoundEngine::playMusicUpdate()
if (m_StreamingAudioInfo.bIs3D)
{
ma_sound_set_spatialization_enabled(&m_musicStream, MA_TRUE);
ma_sound_set_position(&m_musicStream, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z);
if (m_validListenerCount > 1)
{
int iClosestListener = 0;
float fClosestDist = 1e6f;
for (size_t i = 0; i < MAX_LOCAL_PLAYERS; i++)
{
if (m_ListenerA[i].bValid)
{
float dx = m_StreamingAudioInfo.x - m_ListenerA[i].vPosition.x;
float dy = m_StreamingAudioInfo.y - m_ListenerA[i].vPosition.y;
float dz = m_StreamingAudioInfo.z - m_ListenerA[i].vPosition.z;
float dist = sqrtf(dx*dx + dy*dy + dz*dz);
if (dist < fClosestDist)
{
fClosestDist = dist;
iClosestListener = 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;
ma_sound_set_position(&m_musicStream, relX, relY, relZ);
}
else
{
ma_sound_set_position(&m_musicStream, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z);
}
}
else
{
@@ -1344,6 +1441,7 @@ void SoundEngine::playMusicUpdate()
ma_sound_set_volume(&m_musicStream, finalVolume);
ma_result startResult = ma_sound_start(&m_musicStream);
m_bCurrentStreamIsCustom = Minecraft::GetInstance() && Minecraft::GetInstance()->skins->getSelected()->hasAudio();
app.DebugPrintf("ma_sound_start result: %d\n", startResult);
m_StreamState=eMusicStreamState_Playing;
@@ -1370,6 +1468,36 @@ void SoundEngine::playMusicUpdate()
m_StreamState = eMusicStreamState_Idle;
break;
case eMusicStreamState_Fading:
if (m_musicStreamActive)
{
const auto now = std::chrono::steady_clock::now();
const float elapsedSeconds = std::chrono::duration<float>(now - m_musicFadeLastUpdateTime).count();
if (elapsedSeconds > 0.0f)
{
m_musicFadeSecondsRemaining = (elapsedSeconds >= m_musicFadeSecondsRemaining)
? 0.0f
: m_musicFadeSecondsRemaining - elapsedSeconds;
m_musicFadeLastUpdateTime = now;
}
if (m_musicFadeSecondsRemaining > 0.0f)
{
const float fadeFactor = m_musicFadeSecondsRemaining / MUSIC_FADE_DURATION_SECONDS;
const float finalVolume = m_StreamingAudioInfo.volume * getMasterMusicVolume() * fadeFactor;
ma_sound_set_volume(&m_musicStream, finalVolume);
break;
}
ma_sound_stop(&m_musicStream);
ma_sound_uninit(&m_musicStream);
m_musicStreamActive = false;
}
SetIsPlayingStreamingCDMusic(false);
SetIsPlayingStreamingGameMusic(false);
m_StreamState = eMusicStreamState_Idle;
break;
case eMusicStreamState_Stopping:
break;
case eMusicStreamState_Play:
@@ -1557,7 +1685,7 @@ void SoundEngine::playMusicUpdate()
}
else
{
m_musicID = getMusicID(eMusicType_Overworld);
getGameModeMusicID(pMinecraft, i);
SetIsPlayingNetherMusic(false);
SetIsPlayingEndMusic(false);
}
@@ -5,6 +5,7 @@ using namespace std;
#include "../../Minecraft.World/SoundTypes.h"
#include "miniaudio.h"
#include <chrono>
constexpr float SFX_3D_MIN_DISTANCE = 1.0f;
constexpr float SFX_3D_MAX_DISTANCE = 16.0f;
@@ -82,6 +83,7 @@ enum eMusicStreamState
{
eMusicStreamState_Idle=0,
eMusicStreamState_Stop,
eMusicStreamState_Fading,
eMusicStreamState_Stopping,
eMusicStreamState_Opening,
eMusicStreamState_OpeningCancel,
@@ -127,6 +129,9 @@ public:
void GetSoundName(char *szSoundName,int iSound);
#endif
void play(int iSound, float x, float y, float z, float volume, float pitch) override;
MiniAudioSound* startLoopingSound(const wstring& name, float x, float y, float z, float volume, float pitch, bool bIs3D = true);
void updateLoopingSound(MiniAudioSound* sound, float x, float y, float z, float volume, float pitch);
void stopLoopingSound(MiniAudioSound* sound);
void startElytraSound(float x, float y, float z, float volume, float pitch);
void stopElytraSound();
void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true) override;
@@ -160,9 +165,13 @@ private:
#endif
int GetRandomishTrack(int iStart,int iEnd);
bool isCustomMusicRequest(const wstring& name) const;
MiniAudioSound* m_elytraLoopingSound = nullptr;
float m_musicFadeSecondsRemaining;
std::chrono::steady_clock::time_point m_musicFadeLastUpdateTime;
bool m_bCurrentStreamIsCustom;
ma_engine m_engine;
ma_engine_config m_engineConfig;
@@ -90,6 +90,7 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Water_ExtremeHillsEdge",
L"Water_Jungle",
L"Water_JungleHills",
L"Water_JungleEdge",
L"Water_Mesa",
L"Sky_Ocean",
@@ -115,6 +116,7 @@ const wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] =
L"Sky_ExtremeHillsEdge",
L"Sky_Jungle",
L"Sky_JungleHills",
L"Sky_JungleEdge",
L"Tile_RedstoneDust",
L"Tile_RedstoneDustUnlit",
File diff suppressed because it is too large Load Diff
+195 -1
View File
@@ -4,9 +4,94 @@
#include "DLCPack.h"
#include "DLCFile.h"
#include "../../../Minecraft.World/StringHelpers.h"
#include "../../../Minecraft.World/File.h"
#include "../../Minecraft.h"
#include "../../TexturePackRepository.h"
#include "Common/UI/UI.h"
#include "lce_filesystem/FolderFile.h"
static bool isDigitW(wchar_t ch)
{
return ch >= L'0' && ch <= L'9';
}
static bool isDataPackPckName(const wstring &baseNameLower)
{
const wstring suffix = L"data.pck";
if(baseNameLower.size() <= suffix.size() + 1)
{
return false;
}
if(baseNameLower[0] != L'x')
{
return false;
}
if(baseNameLower.compare(baseNameLower.size() - suffix.size(), suffix.size(), suffix) != 0)
{
return false;
}
const size_t digitsStart = 1;
const size_t digitsEnd = baseNameLower.size() - suffix.size();
if(digitsEnd <= digitsStart)
{
return false;
}
for(size_t i = digitsStart; i < digitsEnd; ++i)
{
if(!isDigitW(baseNameLower[i]))
{
return false;
}
}
return true;
}
static bool hasPckFolderFallback(const wstring &path, wstring &folderPath)
{
wstring lowerPath = toLower(path);
const wstring pckSuffix = L".pck";
if(lowerPath.size() <= pckSuffix.size())
{
return false;
}
if(lowerPath.compare(lowerPath.size() - pckSuffix.size(), pckSuffix.size(), pckSuffix) != 0)
{
return false;
}
const size_t nameStart = lowerPath.find_last_of(L"/\\");
const size_t baseOffset = (nameStart == wstring::npos) ? 0 : (nameStart + 1);
wstring baseNameLower = lowerPath.substr(baseOffset);
if(!isDataPackPckName(baseNameLower))
{
return false;
}
folderPath = path.substr(0, path.size() - pckSuffix.size());
return true;
}
static DLCManager::EDLCType getFolderFileType(const wstring &path)
{
wstring lowerPath = toLower(path);
if(lowerPath == L"colours.col" || lowerPath.rfind(L"/colours.col") != wstring::npos)
{
return DLCManager::e_DLCType_ColourTable;
}
if(lowerPath.rfind(L"/languages.loc") != wstring::npos || lowerPath.rfind(L".loc") != wstring::npos)
{
return DLCManager::e_DLCType_LocalisationData;
}
if(lowerPath.rfind(L".xzp") != wstring::npos)
{
return DLCManager::e_DLCType_UIData;
}
if(lowerPath.rfind(L".grf") != wstring::npos)
{
return DLCManager::e_DLCType_GameRulesHeader;
}
return DLCManager::e_DLCType_Texture;
}
const WCHAR *DLCManager::wchTypeNamesA[]=
{
@@ -329,13 +414,47 @@ bool DLCManager::readDLCDataFile(DWORD &dwFilesProcessed, const string &path, DL
}
else if (fromArchive) return false;
wstring finalPathW = wPath;
#ifdef _WINDOWS64
string finalPath = StorageManager.GetMountedPath(path.c_str());
if(finalPath.size() == 0) finalPath = path;
HANDLE file = CreateFile(finalPath.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
finalPathW = convStringToWstring(finalPath);
#elif defined(_DURANGO)
wstring finalPath = StorageManager.GetMountedPath(wPath.c_str());
if(finalPath.size() == 0) finalPath = wPath;
finalPathW = finalPath;
#endif
if(!fromArchive)
{
wstring folderPath;
if(hasPckFolderFallback(finalPathW, folderPath))
{
wstring resolvedFolderPath = folderPath;
#ifdef _WINDOWS64
const char *folderPathA = wstringtofilename(folderPath);
string mountedFolderPath = StorageManager.GetMountedPath(folderPathA);
if(mountedFolderPath.size() > 0)
{
resolvedFolderPath = convStringToWstring(mountedFolderPath);
}
#elif defined(_DURANGO)
wstring mountedFolderPath = StorageManager.GetMountedPath(folderPath.c_str());
if(mountedFolderPath.size() > 0)
{
resolvedFolderPath = mountedFolderPath;
}
#endif
if(readDLCDataFolder(dwFilesProcessed, resolvedFolderPath, pack))
{
return true;
}
}
}
#ifdef _WINDOWS64
HANDLE file = CreateFile(finalPath.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
#elif defined(_DURANGO)
HANDLE file = CreateFile(finalPath.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
#else
HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
@@ -372,6 +491,81 @@ bool DLCManager::readDLCDataFile(DWORD &dwFilesProcessed, const string &path, DL
return processDLCDataFile(dwFilesProcessed, pbData, bytesRead, pack);
}
bool DLCManager::readDLCDataFolder(DWORD &dwFilesProcessed, const wstring &path, DLCPack *pack)
{
File folder(path);
if(!folder.exists() || !folder.isDirectory())
{
return false;
}
FolderFile folderFile(path);
vector<wstring> *fileList = folderFile.getFileList();
if(fileList == nullptr || fileList->empty())
{
delete fileList;
return false;
}
struct FolderEntry
{
wstring rawPath;
wstring normalizedPath;
int size;
};
vector<FolderEntry> entries;
entries.reserve(fileList->size());
unsigned int totalBytes = 0;
for(const auto &rawPath : *fileList)
{
wstring normalized = replaceAll(rawPath, L"\\", L"/");
if(normalized.empty() || normalized == L"0")
{
continue;
}
int size = folderFile.getFileSize(rawPath);
if(size <= 0)
{
continue;
}
entries.push_back({ rawPath, normalized, size });
totalBytes += static_cast<unsigned int>(size);
}
delete fileList;
if(entries.empty() || totalBytes == 0)
{
return false;
}
PBYTE dataBuffer = new BYTE[totalBytes];
pack->SetDataPointer(dataBuffer);
unsigned int offset = 0;
for(const auto &entry : entries)
{
byteArray data = folderFile.getFile(entry.rawPath);
if(data.data == nullptr || data.length == 0)
{
continue;
}
DLCManager::EDLCType type = getFolderFileType(entry.normalizedPath);
DLCFile *dlcFile = pack->addFile(type, entry.normalizedPath);
if(dlcFile != nullptr)
{
memcpy(dataBuffer + offset, data.data, data.length);
dlcFile->addData(dataBuffer + offset, data.length);
offset += data.length;
++dwFilesProcessed;
}
delete [] data.data;
}
return dwFilesProcessed > 0;
}
bool DLCManager::processDLCDataFile(DWORD &dwFilesProcessed, PBYTE pbData, DWORD dwLength, DLCPack *pack)
{
unordered_map<int, EDLCParameterType> parameterMapping;
+1
View File
@@ -94,6 +94,7 @@ public:
bool readDLCDataFile(DWORD &dwFilesProcessed, const wstring &path, DLCPack *pack, bool fromArchive = false);
bool readDLCDataFile(DWORD &dwFilesProcessed, const string &path, DLCPack *pack, bool fromArchive = false);
bool readDLCDataFolder(DWORD &dwFilesProcessed, const wstring &path, DLCPack *pack);
DWORD retrievePackIDFromDLCDataFile(const string &path, DLCPack *pack);
static unsigned short SwapInt16(unsigned short value) {
+22 -9
View File
@@ -416,15 +416,28 @@ bool DLCPack::hasPurchasedFile(DLCManager::EDLCType type, const wstring &path)
void DLCPack::UpdateLanguage()
{
// find the language file
DLCManager::e_DLCType_LocalisationData;
DLCFile *file = nullptr;
if(m_files[DLCManager::e_DLCType_LocalisationData].size() > 0)
if (m_files[DLCManager::e_DLCType_LocalisationData].empty())
{
file = m_files[DLCManager::e_DLCType_LocalisationData][0];
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"));
StringTable *strTable = localisationFile->getStringTable();
strTable->ReloadStringTable();
return;
}
}
DLCFile *file = getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc");
if (!file)
{
file = m_files[DLCManager::e_DLCType_LocalisationData][0];
}
DLCLocalisationFile *localisationFile = static_cast<DLCLocalisationFile *>(file);
if (!localisationFile)
{
return;
}
StringTable *strTable = localisationFile->getStringTable();
if (!strTable)
{
return;
}
strTable->ReloadStringTable();
}
@@ -50,9 +50,9 @@ bool AddEnchantmentRuleDefinition::enchantItem(shared_ptr<ItemInstance> item)
{
// 4J-JEV: Ripped code from enchantmenthelpers
// Maybe we want to add an addEnchantment method to EnchantmentHelpers
if (item->id == Item::enchantedBook_Id)
if (item->id == Item::enchanted_book_Id)
{
Item::enchantedBook->addEnchantment( item, new EnchantmentInstance(m_enchantmentId, m_enchantmentLevel) );
Item::enchanted_book->addEnchantment( item, new EnchantmentInstance(m_enchantmentId, m_enchantmentLevel) );
}
else if (item->isEnchantable())
{
@@ -59,6 +59,7 @@ void GameRuleDefinition::addAttribute(const wstring &attributeName, const wstrin
{
m_descriptionId = attributeValue;
#ifndef _CONTENT_PACKAGE
if (m_descriptionId == L"IDS_COLLECTED_MUSIC_DISCS") m_descriptionId = L"You have found {*progress*} of {*goal*} Music Discs!";
wprintf(L"GameRuleDefinition: Adding parameter descriptionId=%ls\n",m_descriptionId.c_str());
#endif
}
@@ -74,6 +75,11 @@ void GameRuleDefinition::addAttribute(const wstring &attributeName, const wstrin
m_4JDataValue = _fromString<int>(attributeValue);
app.DebugPrintf("GameRuleDefinition: Adding parameter m_4JDataValue=%d\n",m_4JDataValue);
}
else if(attributeName.compare(L"goalType") == 0)
{
m_4JDataValue = _fromString<int>(attributeValue);
app.DebugPrintf("GameRuleDefinition: Adding parameter goalType=%d\n",m_4JDataValue);
}
else
{
#ifndef _CONTENT_PACKAGE
@@ -13,6 +13,7 @@ class ConsoleSchematicFile;
class LevelRuleset;
class BiomeOverride;
class StartFeature;
class DLCPack;
class GrSource
{
@@ -135,6 +136,7 @@ public:
void setBaseSavePath(const wstring &x);
bool ready();
DLCPack *getParentDLCPack() { return m_parentDLCPack; }
void setBaseSaveData(PBYTE pbData, DWORD dwSize);
PBYTE getBaseSaveData(DWORD &size);
@@ -7,7 +7,7 @@
XboxStructureActionPlaceSpawner::XboxStructureActionPlaceSpawner()
{
m_tile = Tile::mobSpawner_Id;
m_tile = Tile::mob_spawner_Id;
m_entityId = L"Pig";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Some files were not shown because too many files have changed in this diff Show More