Merge pull request 'TU31 final blocks + changes' (#9) from Fireblade/neoLegacy:TU31 into main
Reviewed-on: https://git.neolegacy.dev/neoStudiosLCE/neoLegacy/pulls/9
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 413 KiB |
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 182 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 124 KiB |