diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Common/GameRules | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Common/GameRules')
52 files changed, 5607 insertions, 0 deletions
diff --git a/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp new file mode 100644 index 00000000..eabc1401 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.enchantment.h" +#include "AddEnchantmentRuleDefinition.h" + +AddEnchantmentRuleDefinition::AddEnchantmentRuleDefinition() +{ + m_enchantmentId = m_enchantmentLevel = 0; +} + +void AddEnchantmentRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 2); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_enchantmentId); + dos->writeUTF( _toString( m_enchantmentId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_enchantmentLevel); + dos->writeUTF( _toString( m_enchantmentLevel ) ); +} + +void AddEnchantmentRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"enchantmentId") == 0) + { + int value = _fromString<int>(attributeValue); + if(value < 0) value = 0; + if(value >= 256) value = 255; + m_enchantmentId = value; + app.DebugPrintf("AddEnchantmentRuleDefinition: Adding parameter enchantmentId=%d\n",m_enchantmentId); + } + else if(attributeName.compare(L"enchantmentLevel") == 0) + { + int value = _fromString<int>(attributeValue); + if(value < 0) value = 0; + m_enchantmentLevel = value; + app.DebugPrintf("AddEnchantmentRuleDefinition: Adding parameter enchantmentLevel=%d\n",m_enchantmentLevel); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool AddEnchantmentRuleDefinition::enchantItem(shared_ptr<ItemInstance> item) +{ + bool enchanted = false; + if (item != NULL) + { + // 4J-JEV: Ripped code from enchantmenthelpers + // Maybe we want to add an addEnchantment method to EnchantmentHelpers + if (item->id == Item::enchantedBook_Id) + { + Item::enchantedBook->addEnchantment( item, new EnchantmentInstance(m_enchantmentId, m_enchantmentLevel) ); + } + else if (item->isEnchantable()) + { + Enchantment *e = Enchantment::enchantments[m_enchantmentId]; + + if(e != NULL && e->category->canEnchant(item->getItem())) + { + int level = min(e->getMaxLevel(), m_enchantmentLevel); + item->enchant(e, m_enchantmentLevel); + enchanted = true; + } + } + } + return enchanted; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h new file mode 100644 index 00000000..3beece10 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class ItemInstance; + +class AddEnchantmentRuleDefinition : public GameRuleDefinition +{ +private: + int m_enchantmentId; + int m_enchantmentLevel; + +public: + AddEnchantmentRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_AddEnchantment; } + + virtual void writeAttributes(DataOutputStream *, UINT numAttrs); + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool enchantItem(shared_ptr<ItemInstance> item); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp new file mode 100644 index 00000000..0d14884a --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp @@ -0,0 +1,127 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "AddItemRuleDefinition.h" +#include "AddEnchantmentRuleDefinition.h" + +AddItemRuleDefinition::AddItemRuleDefinition() +{ + m_itemId = m_quantity = m_auxValue = m_dataTag = 0; + m_slot = -1; +} + +void AddItemRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_itemId); + dos->writeUTF( _toString( m_itemId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_quantity); + dos->writeUTF( _toString( m_quantity ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_auxValue); + dos->writeUTF( _toString( m_auxValue ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dataTag); + dos->writeUTF( _toString( m_dataTag ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_slot); + dos->writeUTF( _toString( m_slot ) ); +} + +void AddItemRuleDefinition::getChildren(vector<GameRuleDefinition *> *children) +{ + GameRuleDefinition::getChildren( children ); + for (AUTO_VAR(it, m_enchantments.begin()); it != m_enchantments.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *AddItemRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddEnchantment) + { + rule = new AddEnchantmentRuleDefinition(); + m_enchantments.push_back((AddEnchantmentRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + //wprintf(L"AddItemRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void AddItemRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"itemId") == 0) + { + int value = _fromString<int>(attributeValue); + m_itemId = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter itemId=%d\n",m_itemId); + } + else if(attributeName.compare(L"quantity") == 0) + { + int value = _fromString<int>(attributeValue); + m_quantity = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter quantity=%d\n",m_quantity); + } + else if(attributeName.compare(L"auxValue") == 0) + { + int value = _fromString<int>(attributeValue); + m_auxValue = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter auxValue=%d\n",m_auxValue); + } + else if(attributeName.compare(L"dataTag") == 0) + { + int value = _fromString<int>(attributeValue); + m_dataTag = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter dataTag=%d\n",m_dataTag); + } + else if(attributeName.compare(L"slot") == 0) + { + int value = _fromString<int>(attributeValue); + m_slot = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter slot=%d\n",m_slot); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool AddItemRuleDefinition::addItemToContainer(shared_ptr<Container> container, int slotId) +{ + bool added = false; + if(Item::items[m_itemId] != NULL) + { + int quantity = min(m_quantity, Item::items[m_itemId]->getMaxStackSize()); + shared_ptr<ItemInstance> newItem = shared_ptr<ItemInstance>(new ItemInstance(m_itemId,quantity,m_auxValue) ); + newItem->set4JData(m_dataTag); + + for(AUTO_VAR(it, m_enchantments.begin()); it != m_enchantments.end(); ++it) + { + (*it)->enchantItem(newItem); + } + + if(m_slot >= 0 && m_slot < container->getContainerSize() ) + { + container->setItem( m_slot, newItem ); + added = true; + } + else if(slotId >= 0 && slotId < container->getContainerSize() ) + { + container->setItem( slotId, newItem ); + added = true; + } + else if(dynamic_pointer_cast<Inventory>(container) != NULL) + { + added = dynamic_pointer_cast<Inventory>(container)->add(newItem); + } + } + return added; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h new file mode 100644 index 00000000..602f2d82 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h @@ -0,0 +1,30 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class Container; +class AddEnchantmentRuleDefinition; + +class AddItemRuleDefinition : public GameRuleDefinition +{ +private: + int m_itemId; + int m_quantity; + int m_auxValue; + int m_dataTag; + int m_slot; + vector<AddEnchantmentRuleDefinition *> m_enchantments; + +public: + AddItemRuleDefinition(); + + virtual void writeAttributes(DataOutputStream *, UINT numAttributes); + virtual void getChildren(vector<GameRuleDefinition *> *children); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_AddItem; } + + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool addItemToContainer(shared_ptr<Container> container, int slotId); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp new file mode 100644 index 00000000..aa4a8fb2 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp @@ -0,0 +1,249 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "ApplySchematicRuleDefinition.h" +#include "LevelGenerationOptions.h" +#include "ConsoleSchematicFile.h" + +ApplySchematicRuleDefinition::ApplySchematicRuleDefinition(LevelGenerationOptions *levelGenOptions) +{ + m_levelGenOptions = levelGenOptions; + m_location = Vec3::newPermanent(0,0,0); + m_locationBox = NULL; + m_totalBlocksChanged = 0; + m_totalBlocksChangedLighting = 0; + m_rotation = ConsoleSchematicFile::eSchematicRot_0; + m_completed = false; + m_dimension = 0; + m_schematic = NULL; +} + +ApplySchematicRuleDefinition::~ApplySchematicRuleDefinition() +{ + app.DebugPrintf("Deleting ApplySchematicRuleDefinition.\n"); + if(!m_completed) m_levelGenOptions->releaseSchematicFile(m_schematicName); + m_schematic = NULL; + delete m_location; +} + +void ApplySchematicRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_filename); + dos->writeUTF(m_schematicName); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_location->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_location->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_location->z)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_rot); + + switch (m_rotation) + { + case ConsoleSchematicFile::eSchematicRot_0: dos->writeUTF(_toString( 0 )); break; + case ConsoleSchematicFile::eSchematicRot_90: dos->writeUTF(_toString( 90 )); break; + case ConsoleSchematicFile::eSchematicRot_180: dos->writeUTF(_toString( 180 )); break; + case ConsoleSchematicFile::eSchematicRot_270: dos->writeUTF(_toString( 270 )); break; + } +} + +void ApplySchematicRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"filename") == 0) + { + m_schematicName = attributeValue; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter filename=%s\n",m_schematicName.c_str()); + + if(!m_schematicName.empty()) + { + if(m_schematicName.substr( m_schematicName.length() - 4, m_schematicName.length()).compare(L".sch") != 0) + { + m_schematicName.append(L".sch"); + } + m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + } + } + else if(attributeName.compare(L"x") == 0) + { + m_location->x = _fromString<int>(attributeValue); + if( ((int)abs(m_location->x))%2 != 0) m_location->x -=1; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter x=%f\n",m_location->x); + } + else if(attributeName.compare(L"y") == 0) + { + m_location->y = _fromString<int>(attributeValue); + if( ((int)abs(m_location->y))%2 != 0) m_location->y -= 1; + if(m_location->y < 0) m_location->y = 0; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter y=%f\n",m_location->y); + } + else if(attributeName.compare(L"z") == 0) + { + m_location->z = _fromString<int>(attributeValue); + if(((int)abs(m_location->z))%2 != 0) m_location->z -= 1; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter z=%f\n",m_location->z); + } + else if(attributeName.compare(L"rot") == 0) + { + int degrees = _fromString<int>(attributeValue); + + while(degrees < 0) degrees += 360; + while(degrees >= 360) degrees -= 360; + float quad = degrees/90; + degrees = (int)(quad + 0.5f); + switch(degrees) + { + case 1: + m_rotation = ConsoleSchematicFile::eSchematicRot_90; + break; + case 2: + m_rotation = ConsoleSchematicFile::eSchematicRot_180; + break; + case 3: + case 4: + m_rotation = ConsoleSchematicFile::eSchematicRot_270; + break; + case 0: + default: + m_rotation = ConsoleSchematicFile::eSchematicRot_0; + break; + }; + + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter rot=%d\n",m_rotation); + } + else if(attributeName.compare(L"dim") == 0) + { + m_dimension = _fromString<int>(attributeValue); + if(m_dimension > 1 || m_dimension < -1) m_dimension = 0; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter dimension=%d\n",m_dimension); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void ApplySchematicRuleDefinition::updateLocationBox() +{ + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + m_locationBox = AABB::newPermanent(0,0,0,0,0,0); + + m_locationBox->x0 = m_location->x; + m_locationBox->y0 = m_location->y; + m_locationBox->z0 = m_location->z; + + m_locationBox->y1 = m_location->y + m_schematic->getYSize(); + + switch(m_rotation) + { + case ConsoleSchematicFile::eSchematicRot_90: + case ConsoleSchematicFile::eSchematicRot_270: + m_locationBox->x1 = m_location->x + m_schematic->getZSize(); + m_locationBox->z1 = m_location->z + m_schematic->getXSize(); + break; + case ConsoleSchematicFile::eSchematicRot_0: + case ConsoleSchematicFile::eSchematicRot_180: + default: + m_locationBox->x1 = m_location->x + m_schematic->getXSize(); + m_locationBox->z1 = m_location->z + m_schematic->getZSize(); + break; + }; +} + +void ApplySchematicRuleDefinition::processSchematic(AABB *chunkBox, LevelChunk *chunk) +{ + if( m_completed ) return; + if(chunk->level->dimension->id != m_dimension) return; + + PIXBeginNamedEvent(0, "Processing ApplySchematicRuleDefinition"); + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + if(m_locationBox == NULL) updateLocationBox(); + if(chunkBox->intersects( m_locationBox )) + { + m_locationBox->y1 = min((double)Level::maxBuildHeight, m_locationBox->y1 ); + +#ifdef _DEBUG + app.DebugPrintf("Applying schematic %ls to chunk (%d,%d)\n",m_schematicName.c_str(),chunk->x, chunk->z); +#endif + PIXBeginNamedEvent(0,"Applying blocks and data"); + m_totalBlocksChanged += m_schematic->applyBlocksAndData(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // Add the tileEntities + PIXBeginNamedEvent(0,"Applying tile entities"); + m_schematic->applyTileEntities(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // TODO This does not take into account things that go outside the bounds of the world + int targetBlocks = (m_locationBox->x1 - m_locationBox->x0) + * (m_locationBox->y1 - m_locationBox->y0) + * (m_locationBox->z1 - m_locationBox->z0); + if( (m_totalBlocksChanged == targetBlocks) && (m_totalBlocksChangedLighting == targetBlocks) ) + { + m_completed = true; + //m_levelGenOptions->releaseSchematicFile(m_schematicName); + //m_schematic = NULL; + } + } + PIXEndNamedEvent(); +} + +void ApplySchematicRuleDefinition::processSchematicLighting(AABB *chunkBox, LevelChunk *chunk) +{ + if( m_completed ) return; + if(chunk->level->dimension->id != m_dimension) return; + + PIXBeginNamedEvent(0, "Processing ApplySchematicRuleDefinition (lighting)"); + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + if(m_locationBox == NULL) updateLocationBox(); + if(chunkBox->intersects( m_locationBox )) + { + m_locationBox->y1 = min((double)Level::maxBuildHeight, m_locationBox->y1 ); + +#ifdef _DEBUG + app.DebugPrintf("Applying schematic %ls to chunk (%d,%d)\n",m_schematicName.c_str(),chunk->x, chunk->z); +#endif + PIXBeginNamedEvent(0,"Patching lighting"); + m_totalBlocksChangedLighting += m_schematic->applyLighting(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // TODO This does not take into account things that go outside the bounds of the world + int targetBlocks = (m_locationBox->x1 - m_locationBox->x0) + * (m_locationBox->y1 - m_locationBox->y0) + * (m_locationBox->z1 - m_locationBox->z0); + if( (m_totalBlocksChanged == targetBlocks) && (m_totalBlocksChangedLighting == targetBlocks) ) + { + m_completed = true; + //m_levelGenOptions->releaseSchematicFile(m_schematicName); + //m_schematic = NULL; + } + } + PIXEndNamedEvent(); +} + +bool ApplySchematicRuleDefinition::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + if( m_locationBox == NULL ) updateLocationBox(); + return m_locationBox->intersects(x0,y0,z0,x1,y1,z1); +} + +int ApplySchematicRuleDefinition::getMinY() +{ + if( m_locationBox == NULL ) updateLocationBox(); + return m_locationBox->y0; +} + +void ApplySchematicRuleDefinition::reset() +{ + m_totalBlocksChanged = 0; + m_totalBlocksChangedLighting = 0; + m_completed = false; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h new file mode 100644 index 00000000..21c42dea --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h @@ -0,0 +1,51 @@ +#pragma once +#include "GameRuleDefinition.h" +#include "ConsoleSchematicFile.h" + +class AABB; +class Vec3; +class LevelChunk; +class LevelGenerationOptions; +class GRFObject; + +class ApplySchematicRuleDefinition : public GameRuleDefinition +{ +private: + LevelGenerationOptions *m_levelGenOptions; + wstring m_schematicName; + ConsoleSchematicFile *m_schematic; + Vec3 *m_location; + AABB *m_locationBox; + ConsoleSchematicFile::ESchematicRotation m_rotation; + int m_dimension; + + __int64 m_totalBlocksChanged; + __int64 m_totalBlocksChangedLighting; + bool m_completed; + + void updateLocationBox(); +public: + ApplySchematicRuleDefinition(LevelGenerationOptions *levelGenOptions); + ~ApplySchematicRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_ApplySchematic; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + void processSchematic(AABB *chunkBox, LevelChunk *chunk); + void processSchematicLighting(AABB *chunkBox, LevelChunk *chunk); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + int getMinY(); + + bool isComplete() { return m_completed; } + + wstring getSchematicName() { return m_schematicName; } + + /** 4J-JEV: + * This GameRuleDefinition contains limited game state. + * Reset any state to how it should be before a new game. + */ + void reset(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/BiomeOverride.cpp b/Minecraft.Client/Common/GameRules/BiomeOverride.cpp new file mode 100644 index 00000000..22cc0c7a --- /dev/null +++ b/Minecraft.Client/Common/GameRules/BiomeOverride.cpp @@ -0,0 +1,59 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "BiomeOverride.h" + +BiomeOverride::BiomeOverride() +{ + m_tile = 0; + m_topTile = 0; + m_biomeId = 0; +} + +void BiomeOverride::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_biomeId); + dos->writeUTF(_toString(m_biomeId)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_tileId); + dos->writeUTF(_toString(m_tile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_topTileId); + dos->writeUTF(_toString(m_topTile)); +} + +void BiomeOverride::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"tileId") == 0) + { + int value = _fromString<int>(attributeValue); + m_tile = value; + app.DebugPrintf("BiomeOverride: Adding parameter tileId=%d\n",m_tile); + } + else if(attributeName.compare(L"topTileId") == 0) + { + int value = _fromString<int>(attributeValue); + m_topTile = value; + app.DebugPrintf("BiomeOverride: Adding parameter topTileId=%d\n",m_topTile); + } + else if(attributeName.compare(L"biomeId") == 0) + { + int value = _fromString<int>(attributeValue); + m_biomeId = value; + app.DebugPrintf("BiomeOverride: Adding parameter biomeId=%d\n",m_biomeId); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool BiomeOverride::isBiome(int id) +{ + return m_biomeId == id; +} + +void BiomeOverride::getTileValues(BYTE &tile, BYTE &topTile) +{ + if(m_tile != 0) tile = (BYTE)m_tile; + if(m_topTile != 0) topTile = (BYTE)m_topTile; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/BiomeOverride.h b/Minecraft.Client/Common/GameRules/BiomeOverride.h new file mode 100644 index 00000000..5ad9263c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/BiomeOverride.h @@ -0,0 +1,23 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" + +class BiomeOverride : public GameRuleDefinition +{ +private: + BYTE m_topTile; + BYTE m_tile; + int m_biomeId; + +public: + BiomeOverride(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_BiomeOverride; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool isBiome(int id); + void getTileValues(BYTE &tile, BYTE &topTile); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp new file mode 100644 index 00000000..66abefbb --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp @@ -0,0 +1,117 @@ +#include "stdafx.h" +#include "..\..\WstringLookup.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "CollectItemRuleDefinition.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\Connection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" + +CollectItemRuleDefinition::CollectItemRuleDefinition() +{ + m_itemId = 0; + m_auxValue = 0; + m_quantity = 0; +} + +CollectItemRuleDefinition::~CollectItemRuleDefinition() +{ +} + +void CollectItemRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_itemId); + dos->writeUTF( _toString( m_itemId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_auxValue); + dos->writeUTF( _toString( m_auxValue ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_quantity); + dos->writeUTF( _toString( m_quantity ) ); +} + +void CollectItemRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"itemId") == 0) + { + m_itemId = _fromString<int>(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter itemId=%d\n",m_itemId); + } + else if(attributeName.compare(L"auxValue") == 0) + { + m_auxValue = _fromString<int>(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter m_auxValue=%d\n",m_auxValue); + } + else if(attributeName.compare(L"quantity") == 0) + { + m_quantity = _fromString<int>(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter m_quantity=%d\n",m_quantity); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +int CollectItemRuleDefinition::getGoal() +{ + return m_quantity; +} + +int CollectItemRuleDefinition::getProgress(GameRule *rule) +{ + GameRule::ValueType value = rule->getParameter(L"iQuantity"); + return value.i; +} + +void CollectItemRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule::ValueType value; + value.i = 0; + rule->setParameter(L"iQuantity",value); + + GameRuleDefinition::populateGameRule(type, rule); +} + +bool CollectItemRuleDefinition::onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item) +{ + bool statusChanged = false; + if(item != NULL && item->id == m_itemId && item->getAuxValue() == m_auxValue && item->get4JData() == m_4JDataValue) + { + if(!getComplete(rule)) + { + GameRule::ValueType value = rule->getParameter(L"iQuantity"); + int quantityCollected = (value.i += item->count); + rule->setParameter(L"iQuantity",value); + + statusChanged = true; + + if(quantityCollected >= m_quantity) + { + setComplete(rule, true); + app.DebugPrintf("Completed CollectItemRule with info - itemId:%d, auxValue:%d, quantity:%d, dataTag:%d\n", m_itemId,m_auxValue,m_quantity,m_4JDataValue); + + if(rule->getConnection() != NULL) + { + rule->getConnection()->send( shared_ptr<UpdateGameRuleProgressPacket>( new UpdateGameRuleProgressPacket(getActionType(), this->m_descriptionId, m_itemId, m_auxValue, this->m_4JDataValue,NULL,0))); + } + } + } + } + return statusChanged; +} + +wstring CollectItemRuleDefinition::generateXml(shared_ptr<ItemInstance> item) +{ + // 4J Stu - This should be kept in sync with the GameRulesDefinition.xsd + wstring xml = L""; + if(item != NULL) + { + xml = L"<CollectItemRule itemId=\"" + _toString<int>(item->id) + L"\" quantity=\"SET\" descriptionName=\"OPTIONAL\" promptName=\"OPTIONAL\""; + if(item->getAuxValue() != 0) xml += L" auxValue=\"" + _toString<int>(item->getAuxValue()) + L"\""; + if(item->get4JData() != 0) xml += L" dataTag=\"" + _toString<int>(item->get4JData()) + L"\""; + xml += L"/>\n"; + } + return xml; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h new file mode 100644 index 00000000..5ee6f4c5 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h @@ -0,0 +1,40 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class Pos; +class UseTileRuleDefinition; +class ItemInstance; + +class CollectItemRuleDefinition : public GameRuleDefinition +{ +private: + // These values should map directly to the xsd definition for this Rule + int m_itemId; + unsigned char m_auxValue; + int m_quantity; + +public: + CollectItemRuleDefinition(); + ~CollectItemRuleDefinition(); + + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_CollectItemRule; } + + virtual void writeAttributes(DataOutputStream *, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual int getGoal(); + virtual int getProgress(GameRule *rule); + + virtual int getIcon() { return m_itemId; } + virtual int getAuxValue() { return m_auxValue; } + + void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + bool onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item); + + static wstring generateXml(shared_ptr<ItemInstance> item); + +private: + //static wstring generateXml(CollectItemRuleDefinition *ruleDef); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp new file mode 100644 index 00000000..adaf70c8 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "CompleteAllRuleDefinition.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Connection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" + +void CompleteAllRuleDefinition::getChildren(vector<GameRuleDefinition *> *children) +{ + CompoundGameRuleDefinition::getChildren(children); +} + +bool CompleteAllRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = CompoundGameRuleDefinition::onUseTile(rule,tileId,x,y,z); + if(statusChanged) updateStatus(rule); + return statusChanged; +} + +bool CompleteAllRuleDefinition::onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item) +{ + bool statusChanged = CompoundGameRuleDefinition::onCollectItem(rule,item); + if(statusChanged) updateStatus(rule); + return statusChanged; +} + +void CompleteAllRuleDefinition::updateStatus(GameRule *rule) +{ + int goal = 0; + int progress = 0; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + goal += it->second.gr->getGameRuleDefinition()->getGoal(); + progress += it->second.gr->getGameRuleDefinition()->getProgress(it->second.gr); + } + } + if(rule->getConnection() != NULL) + { + PacketData data; + data.goal = goal; + data.progress = progress; + + int icon = -1; + int auxValue = 0; + + if(m_lastRuleStatusChanged != NULL) + { + icon = m_lastRuleStatusChanged->getIcon(); + auxValue = m_lastRuleStatusChanged->getAuxValue(); + m_lastRuleStatusChanged = NULL; + } + rule->getConnection()->send( shared_ptr<UpdateGameRuleProgressPacket>( new UpdateGameRuleProgressPacket(getActionType(), this->m_descriptionId,icon, auxValue, 0,&data,sizeof(PacketData)))); + } + app.DebugPrintf("Updated CompleteAllRule - Completed %d of %d\n", progress, goal); +} + +wstring CompleteAllRuleDefinition::generateDescriptionString(const wstring &description, void *data, int dataLength) +{ + PacketData *values = (PacketData *)data; + wstring newDesc = description; + newDesc = replaceAll(newDesc,L"{*progress*}",_toString<int>(values->progress)); + newDesc = replaceAll(newDesc,L"{*goal*}",_toString<int>(values->goal)); + return newDesc; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h new file mode 100644 index 00000000..b2cb8847 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CompoundGameRuleDefinition.h" + +class CompleteAllRuleDefinition : public CompoundGameRuleDefinition +{ +private: + typedef struct _packetData + { + int goal; + int progress; + } PacketData; + +public: + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_CompleteAllRule; } + + virtual void getChildren(vector<GameRuleDefinition *> *children); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); + virtual bool onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item); + + static wstring generateDescriptionString(const wstring &description, void *data, int dataLength); + +private: + void updateStatus(GameRule *rule); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp new file mode 100644 index 00000000..0481a54b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp @@ -0,0 +1,118 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "CompoundGameRuleDefinition.h" +#include "ConsoleGameRules.h" + +CompoundGameRuleDefinition::CompoundGameRuleDefinition() +{ + m_lastRuleStatusChanged = NULL; +} + +CompoundGameRuleDefinition::~CompoundGameRuleDefinition() +{ + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + delete (*it); + } +} + +void CompoundGameRuleDefinition::getChildren(vector<GameRuleDefinition *> *children) +{ + GameRuleDefinition::getChildren(children); + for (AUTO_VAR(it, m_children.begin()); it != m_children.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *CompoundGameRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_CompleteAllRule) + { + rule = new CompleteAllRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_CollectItemRule) + { + rule = new CollectItemRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_UseTileRule) + { + rule = new UseTileRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_UpdatePlayerRule) + { + rule = new UpdatePlayerRuleDefinition(); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"CompoundGameRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + if(rule != NULL) m_children.push_back(rule); + return rule; +} + +void CompoundGameRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule *newRule = NULL; + int i = 0; + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + newRule = new GameRule(*it, rule->getConnection() ); + (*it)->populateGameRule(type,newRule); + + GameRule::ValueType value; + value.gr = newRule; + value.isPointer = true; + + // Somehow add the newRule to the current rule + rule->setParameter(L"rule" + _toString<int>(i),value); + ++i; + } + GameRuleDefinition::populateGameRule(type, rule); +} + +bool CompoundGameRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = false; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + bool changed = it->second.gr->getGameRuleDefinition()->onUseTile(it->second.gr,tileId,x,y,z); + if(!statusChanged && changed) + { + m_lastRuleStatusChanged = it->second.gr->getGameRuleDefinition(); + statusChanged = true; + } + } + } + return statusChanged; +} + +bool CompoundGameRuleDefinition::onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item) +{ + bool statusChanged = false; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + bool changed = it->second.gr->getGameRuleDefinition()->onCollectItem(it->second.gr,item); + if(!statusChanged && changed) + { + m_lastRuleStatusChanged = it->second.gr->getGameRuleDefinition(); + statusChanged = true; + } + } + } + return statusChanged; +} + +void CompoundGameRuleDefinition::postProcessPlayer(shared_ptr<Player> player) +{ + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + (*it)->postProcessPlayer(player); + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h new file mode 100644 index 00000000..bfedfd09 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class CompoundGameRuleDefinition : public GameRuleDefinition +{ +protected: + vector<GameRuleDefinition *> m_children; +protected: + GameRuleDefinition *m_lastRuleStatusChanged; +public: + CompoundGameRuleDefinition(); + virtual ~CompoundGameRuleDefinition(); + + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); + virtual bool onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item); + virtual void postProcessPlayer(shared_ptr<Player> player); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGameRules.h b/Minecraft.Client/Common/GameRules/ConsoleGameRules.h new file mode 100644 index 00000000..41c5e557 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGameRules.h @@ -0,0 +1,32 @@ +#pragma once +#include "ConsoleGameRulesConstants.h" + +#include "GameRuleManager.h" + +#include "GameRule.h" + +#include "GameRuleDefinition.h" + +#include "LevelRuleset.h" +#include "NamedAreaRuleDefinition.h" + +#include "CollectItemRuleDefinition.h" +#include "CompleteAllRuleDefinition.h" +#include "CompoundGameRuleDefinition.h" +#include "UseTileRuleDefinition.h" +#include "UpdatePlayerRuleDefinition.h" +#include "AddItemRuleDefinition.h" +#include "AddEnchantmentRuleDefinition.h" + +#include "LevelGenerationOptions.h" +#include "ApplySchematicRuleDefinition.h" +#include "ConsoleGenerateStructure.h" +#include "ConsoleGenerateStructureAction.h" +#include "XboxStructureActionGenerateBox.h" +#include "XboxStructureActionPlaceBlock.h" +#include "XboxStructureActionPlaceContainer.h" +#include "XboxStructureActionPlaceSpawner.h" +#include "BiomeOverride.h" +#include "StartFeature.h" + +#include "GameRulesInstance.h" diff --git a/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h b/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h new file mode 100644 index 00000000..a7111f04 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h @@ -0,0 +1,119 @@ +#pragma once + +//#include " + +class ConsoleGameRules +{ +public: + enum EGameRuleType + { + eGameRuleType_Invalid = -1, + eGameRuleType_Root = 0, // This is the top level rule that defines a game mode, this is used to generate data for new players + + eGameRuleType_LevelGenerationOptions, + eGameRuleType_ApplySchematic, + eGameRuleType_GenerateStructure, + eGameRuleType_GenerateBox, + eGameRuleType_PlaceBlock, + eGameRuleType_PlaceContainer, + eGameRuleType_PlaceSpawner, + eGameRuleType_BiomeOverride, + eGameRuleType_StartFeature, + + eGameRuleType_AddItem, + eGameRuleType_AddEnchantment, + + eGameRuleType_LevelRules, + eGameRuleType_NamedArea, + + eGameRuleType_UseTileRule, + eGameRuleType_CollectItemRule, + eGameRuleType_CompleteAllRule, + eGameRuleType_UpdatePlayerRule, + + eGameRuleType_Count + }; + + enum EGameRuleAttr + { + eGameRuleAttr_Invalid = -1, + + eGameRuleAttr_descriptionName = 0, + eGameRuleAttr_promptName, + eGameRuleAttr_dataTag, + + eGameRuleAttr_enchantmentId, + eGameRuleAttr_enchantmentLevel, + + eGameRuleAttr_itemId, + eGameRuleAttr_quantity, + eGameRuleAttr_auxValue, + eGameRuleAttr_slot, + + eGameRuleAttr_name, + + eGameRuleAttr_food, + eGameRuleAttr_health, + + eGameRuleAttr_tileId, + eGameRuleAttr_useCoords, + + eGameRuleAttr_seed, + eGameRuleAttr_flatworld, + + eGameRuleAttr_filename, + eGameRuleAttr_rot, + + eGameRuleAttr_data, + eGameRuleAttr_block, + eGameRuleAttr_entity, + + eGameRuleAttr_facing, + + eGameRuleAttr_edgeTile, + eGameRuleAttr_fillTile, + eGameRuleAttr_skipAir, + + eGameRuleAttr_x, + eGameRuleAttr_x0, + eGameRuleAttr_x1, + + eGameRuleAttr_y, + eGameRuleAttr_y0, + eGameRuleAttr_y1, + + eGameRuleAttr_z, + eGameRuleAttr_z0, + eGameRuleAttr_z1, + + eGameRuleAttr_chunkX, + eGameRuleAttr_chunkZ, + + eGameRuleAttr_yRot, + + eGameRuleAttr_spawnX, + eGameRuleAttr_spawnY, + eGameRuleAttr_spawnZ, + + eGameRuleAttr_orientation, + eGameRuleAttr_dimension, + + eGameRuleAttr_topTileId, + eGameRuleAttr_biomeId, + + eGameRuleAttr_feature, + + eGameRuleAttr_Count + }; + + static void write(DataOutputStream *dos, ConsoleGameRules::EGameRuleType eType) + { + dos->writeInt(eType); + } + + static void write(DataOutputStream *dos, ConsoleGameRules::EGameRuleAttr eAttr) + { + dos->writeInt( eGameRuleType_Count + eAttr ); + } + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp new file mode 100644 index 00000000..0476b0e3 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp @@ -0,0 +1,181 @@ +#include "stdafx.h" +#include "ConsoleGenerateStructure.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.h" + +ConsoleGenerateStructure::ConsoleGenerateStructure() : StructurePiece(0) +{ + m_x = m_y = m_z = 0; + boundingBox = NULL; + orientation = Direction::NORTH; + m_dimension = 0; +} + +void ConsoleGenerateStructure::getChildren(vector<GameRuleDefinition *> *children) +{ + GameRuleDefinition::getChildren(children); + + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *ConsoleGenerateStructure::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_GenerateBox) + { + rule = new XboxStructureActionGenerateBox(); + m_actions.push_back((XboxStructureActionGenerateBox *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceBlock) + { + rule = new XboxStructureActionPlaceBlock(); + m_actions.push_back((XboxStructureActionPlaceBlock *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceContainer) + { + rule = new XboxStructureActionPlaceContainer(); + m_actions.push_back((XboxStructureActionPlaceContainer *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceSpawner) + { + rule = new XboxStructureActionPlaceSpawner(); + m_actions.push_back((XboxStructureActionPlaceSpawner *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"ConsoleGenerateStructure: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void ConsoleGenerateStructure::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_orientation); + dos->writeUTF(_toString(orientation)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dimension); + dos->writeUTF(_toString(m_dimension)); +} + +void ConsoleGenerateStructure::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x") == 0) + { + int value = _fromString<int>(attributeValue); + m_x = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter x=%d\n",m_x); + } + else if(attributeName.compare(L"y") == 0) + { + int value = _fromString<int>(attributeValue); + m_y = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter y=%d\n",m_y); + } + else if(attributeName.compare(L"z") == 0) + { + int value = _fromString<int>(attributeValue); + m_z = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter z=%d\n",m_z); + } + else if(attributeName.compare(L"orientation") == 0) + { + int value = _fromString<int>(attributeValue); + orientation = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter orientation=%d\n",orientation); + } + else if(attributeName.compare(L"dim") == 0) + { + m_dimension = _fromString<int>(attributeValue); + if(m_dimension > 1 || m_dimension < -1) m_dimension = 0; + app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter dimension=%d\n",m_dimension); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +BoundingBox* ConsoleGenerateStructure::getBoundingBox() +{ + if(boundingBox == NULL) + { + // Find the max bounds + int maxX, maxY, maxZ; + maxX = maxY = maxZ = 1; + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); ++it) + { + ConsoleGenerateStructureAction *action = *it; + maxX = max(maxX,action->getEndX()); + maxY = max(maxY,action->getEndY()); + maxZ = max(maxZ,action->getEndZ()); + } + + boundingBox = new BoundingBox(m_x, m_y, m_z, m_x + maxX, m_y + maxY, m_z + maxZ); + } + return boundingBox; +} + +bool ConsoleGenerateStructure::postProcess(Level *level, Random *random, BoundingBox *chunkBB) +{ + if(level->dimension->id != m_dimension) return false; + + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); ++it) + { + ConsoleGenerateStructureAction *action = *it; + + switch(action->getActionType()) + { + case ConsoleGameRules::eGameRuleType_GenerateBox: + { + XboxStructureActionGenerateBox *genBox = (XboxStructureActionGenerateBox *)action; + genBox->generateBoxInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceBlock: + { + XboxStructureActionPlaceBlock *pPlaceBlock = (XboxStructureActionPlaceBlock *)action; + pPlaceBlock->placeBlockInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceContainer: + { + XboxStructureActionPlaceContainer *pPlaceContainer = (XboxStructureActionPlaceContainer *)action; + pPlaceContainer->placeContainerInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceSpawner: + { + XboxStructureActionPlaceSpawner *pPlaceSpawner = (XboxStructureActionPlaceSpawner *)action; + pPlaceSpawner->placeSpawnerInLevel(this,level,chunkBB); + } + break; + }; + } + + return false; +} + +bool ConsoleGenerateStructure::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + return getBoundingBox()->intersects(x0,y0,z0,x1,y1,z1); +} + +int ConsoleGenerateStructure::getMinY() +{ + return getBoundingBox()->y0; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h new file mode 100644 index 00000000..5b97b108 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h @@ -0,0 +1,38 @@ +#pragma once +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructurePiece.h" + +class Level; +class Random; +class BoundingBox; +class ConsoleGenerateStructureAction; +class XboxStructureActionPlaceContainer; +class GRFObject; + +class ConsoleGenerateStructure : public GameRuleDefinition, public StructurePiece +{ +private: + int m_x, m_y, m_z; + vector<ConsoleGenerateStructureAction *> m_actions; + int m_dimension; +public: + ConsoleGenerateStructure(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_GenerateStructure; } + + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + // StructurePiece + virtual BoundingBox *getBoundingBox(); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + void createContainer(XboxStructureActionPlaceContainer *action, Level *level, BoundingBox *chunkBB); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + + virtual int getMinY(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h new file mode 100644 index 00000000..14eb2fd8 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h @@ -0,0 +1,11 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class ConsoleGenerateStructureAction : public GameRuleDefinition +{ +public: + virtual int getEndX() = 0; + virtual int getEndY() = 0; + virtual int getEndZ() = 0; +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp new file mode 100644 index 00000000..4a4e27b2 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp @@ -0,0 +1,1020 @@ +#include "stdafx.h" +#include <vector> +#include "..\..\..\Minecraft.World\com.mojang.nbt.h" +#include "..\..\..\Minecraft.World\System.h" +#include "ConsoleSchematicFile.h" +#include "..\..\..\Minecraft.World\InputOutputStream.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\compression.h" + +ConsoleSchematicFile::ConsoleSchematicFile() +{ + m_xSize = m_ySize = m_zSize = 0; + m_refCount = 1; + m_data.data = NULL; +} + +ConsoleSchematicFile::~ConsoleSchematicFile() +{ + app.DebugPrintf("Deleting schematic file\n"); + if(m_data.data != NULL) delete [] m_data.data; +} + +void ConsoleSchematicFile::save(DataOutputStream *dos) +{ + if(dos != NULL) + { + dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION); + + dos->writeByte(APPROPRIATE_COMPRESSION_TYPE); + + dos->writeInt(m_xSize); + dos->writeInt(m_ySize); + dos->writeInt(m_zSize); + + byteArray ba(new BYTE[ m_data.length ], m_data.length); + Compression::getCompression()->CompressLZXRLE( ba.data, &ba.length, + m_data.data, m_data.length); + + dos->writeInt(ba.length); + dos->write(ba); + + save_tags(dos); + + delete [] ba.data; + } +} + +void ConsoleSchematicFile::load(DataInputStream *dis) +{ + if(dis != NULL) + { + // VERSION CHECK // + int version = dis->readInt(); + + Compression::ECompressionTypes compressionType = Compression::eCompressionType_LZXRLE; + + if (version > XBOX_SCHEMATIC_ORIGINAL_VERSION) // Or later versions + { + compressionType = (Compression::ECompressionTypes)dis->readByte(); + } + + if (version > XBOX_SCHEMATIC_CURRENT_VERSION) + assert(false && "Unrecognised schematic version!!"); + + m_xSize = dis->readInt(); + m_ySize = dis->readInt(); + m_zSize = dis->readInt(); + + int compressedSize = dis->readInt(); + byteArray compressedBuffer(compressedSize); + dis->readFully(compressedBuffer); + + if(m_data.data != NULL) + { + delete [] m_data.data; + m_data.data = NULL; + } + + if(compressionType == Compression::eCompressionType_None) + { + m_data = compressedBuffer; + } + else + { + unsigned int outputSize = m_xSize * m_ySize * m_zSize * 3/2; + m_data = byteArray(outputSize); + + switch(compressionType) + { + case Compression::eCompressionType_RLE: + Compression::getCompression()->DecompressRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + break; + case APPROPRIATE_COMPRESSION_TYPE: + Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + break; + default: + app.DebugPrintf("Unrecognized compression type for Schematic file (%d)\n", (int)compressionType); + Compression::getCompression()->SetDecompressionType( (Compression::ECompressionTypes)compressionType ); + Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + Compression::getCompression()->SetDecompressionType( APPROPRIATE_COMPRESSION_TYPE ); + }; + + delete [] compressedBuffer.data; + } + + // READ TAGS // + CompoundTag *tag = NbtIo::read(dis); + ListTag<CompoundTag> *tileEntityTags = (ListTag<CompoundTag> *) tag->getList(L"TileEntities"); + if (tileEntityTags != NULL) + { + for (int i = 0; i < tileEntityTags->size(); i++) + { + CompoundTag *teTag = tileEntityTags->get(i); + shared_ptr<TileEntity> te = TileEntity::loadStatic(teTag); + + if(te == NULL) + { +#ifndef _CONTENT_PACKAGE + app.DebugPrintf("ConsoleSchematicFile has read a NULL tile entity\n"); + __debugbreak(); +#endif + } + else + { + m_tileEntities.push_back(te); + } + } + } + ListTag<CompoundTag> *entityTags = (ListTag<CompoundTag> *) tag->getList(L"Entities"); + if (entityTags != NULL) + { + for (int i = 0; i < entityTags->size(); i++) + { + CompoundTag *eTag = entityTags->get(i); + eINSTANCEOF type = EntityIO::getType(eTag->getString(L"id")); + ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) eTag->getList(L"Pos"); + + double x = pos->get(0)->data; + double y = pos->get(1)->data; + double z = pos->get(2)->data; + + if( type == eTYPE_PAINTING || type == eTYPE_ITEM_FRAME ) + { + x = ((IntTag *) eTag->get(L"TileX") )->data; + y = ((IntTag *) eTag->get(L"TileY") )->data; + z = ((IntTag *) eTag->get(L"TileZ") )->data; + } +#ifdef _DEBUG + //app.DebugPrintf(1,"Loaded entity type %d at (%f,%f,%f)\n",(int)type,x,y,z); +#endif + m_entities.push_back( pair<Vec3 *, CompoundTag *>(Vec3::newPermanent(x,y,z),(CompoundTag *)eTag->copy())); + } + } + delete tag; + } +} + +void ConsoleSchematicFile::save_tags(DataOutputStream *dos) +{ + CompoundTag *tag = new CompoundTag(); + + ListTag<CompoundTag> *tileEntityTags = new ListTag<CompoundTag>(); + tag->put(L"TileEntities", tileEntityTags); + + for (AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end(); it++) + { + CompoundTag *cTag = new CompoundTag(); + (*it)->save(cTag); + tileEntityTags->add(cTag); + } + + ListTag<CompoundTag> *entityTags = new ListTag<CompoundTag>(); + tag->put(L"Entities", entityTags); + + for (AUTO_VAR(it, m_entities.begin()); it != m_entities.end(); it++) + entityTags->add( (CompoundTag *)(*it).second->copy() ); + + NbtIo::write(tag,dos); + delete tag; +} + +__int64 ConsoleSchematicFile::applyBlocksAndData(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + int xStart = max(destinationBox->x0, (double)chunk->x*16); + int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16); + + int yStart = destinationBox->y0; + int yEnd = destinationBox->y1; + if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight; + + int zStart = max(destinationBox->z0, (double)chunk->z*16); + int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16); + +#ifdef _DEBUG + app.DebugPrintf("Range is (%d,%d,%d) to (%d,%d,%d)\n",xStart,yStart,zStart,xEnd-1,yEnd-1,zEnd-1); +#endif + + int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); + int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded; + + int rowBlockCount = getYSize() * getZSize(); + int totalBlockCount = getXSize() * rowBlockCount; + + byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); + PIXBeginNamedEvent(0,"Getting block data"); + chunk->getBlockData(blockData); + PIXEndNamedEvent(); + byteArray dataData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + PIXBeginNamedEvent(0,"Getting Data data"); + chunk->getDataData(dataData); + PIXEndNamedEvent(); + + // Ignore light data + int blockLightP = -1; + int skyLightP = -1; + if( rot == eSchematicRot_90 || rot == eSchematicRot_180 || rot == eSchematicRot_270 ) + { + int schematicXRow = 0; + int schematicZRow = 0; + int blocksP = 0; + int dataP = 0; + + for(int x = xStart; x < xEnd; ++x) + { + int x0 = x - chunk->x*16; + int x1 = x0 + 1; + + for(int z = zStart; z < zEnd; ++z) + { + int z0 = z - chunk->z*16; + int z1 = z0 + 1; + + chunkCoordToSchematicCoord(destinationBox, x, z, rot, schematicXRow, schematicZRow); + blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); + dataP = totalBlockCount + (blocksP)/2; + + ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); + } + } + } + else if( rot == eSchematicRot_0 ) + { + // The initial pointer offsets for the different data types + int schematicXRow = xStart - destinationBox->x0; + int schematicZRow = zStart - destinationBox->z0; + int blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); + int dataP = totalBlockCount + (schematicXRow*rowBlockCount + (schematicZRow*getYSize()))/2; + + for(int x = xStart; x < xEnd; ++x) + { + int x0 = x - chunk->x*16; + int x1 = x0 + 1; + + int z0 = zStart - chunk->z*16; + int z1 = zEnd - chunk->z*16; + + ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); + // update all pointer positions + // For z start to z end + // Set blocks and data + // increment z by the right amount + blocksP += (rowBlockCount-rowBlocksIncluded); + dataP += (rowBlockCount-rowBlocksIncluded)/2; + } + } + else + { + app.DebugPrintf("ERROR: Rotation of block and data not implemented!!\n"); + } + + // 4J Stu - Hack for ME pack to replace sand with end stone in schematics + //for(int i = 0; i < blockData.length; ++i) + //{ + // if(blockData[i] == Tile::sand_Id || blockData[i] == Tile::sandStone_Id) + // { + // blockData[i] = Tile::whiteStone_Id; + // } + //} + + PIXBeginNamedEvent(0,"Setting Block data"); + chunk->setBlockData(blockData); + PIXEndNamedEvent(); + delete blockData.data; + chunk->recalcHeightmapOnly(); + PIXBeginNamedEvent(0,"Setting Data data"); + chunk->setDataData(dataData); + PIXEndNamedEvent(); + delete dataData.data; + + // A basic pass through to roughly do the lighting. At this point of post-processing, we don't have all the neighbouring chunks loaded in, + // so any lighting here should be things that won't propagate out of this chunk. + for( int xx = xStart ; xx < xEnd; xx++ ) + for( int y = yStart ; y < yEnd; y++ ) + for( int zz = zStart ; zz < zEnd; zz++ ) + { + int x = xx - chunk->x * 16; + int z = zz - chunk->z * 16; + chunk->setBrightness(LightLayer::Block,x,y,z,0); + if( chunk->getTile(x,y,z) ) + { + chunk->setBrightness(LightLayer::Sky,x,y,z,0); + } + else + { + if( chunk->isSkyLit(x,y,z) ) + { + chunk->setBrightness(LightLayer::Sky,x,y,z,15); + } + else + { + chunk->setBrightness(LightLayer::Sky,x,y,z,0); + } + } + } + + return blocksIncluded; +} + +// At the point that this is called, we have all the neighbouring chunks loaded in (and generally post-processed, apart from this lighting pass), so +// we can do the sort of lighting that might propagate out of the chunk. +__int64 ConsoleSchematicFile::applyLighting(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + int xStart = max(destinationBox->x0, (double)chunk->x*16); + int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16); + + int yStart = destinationBox->y0; + int yEnd = destinationBox->y1; + if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight; + + int zStart = max(destinationBox->z0, (double)chunk->z*16); + int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16); + + int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); + int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded; + + // Now actually do a checkLight on blocks that might need it, which should more accurately put everything in place + for( int xx = xStart ; xx < xEnd; xx++ ) + for( int y = yStart ; y < yEnd; y++ ) + for( int zz = zStart ; zz < zEnd; zz++ ) + { + int x = xx - chunk->x * 16; + int z = zz - chunk->z * 16; + + if( y <= chunk->getHeightmap( x, z ) ) + { + chunk->level->checkLight(LightLayer::Sky, xx, y, zz, true); + } + if( Tile::lightEmission[chunk->getTile(x,y,z)] ) + { + // Note that this lighting passes a rootOnlyEmissive flag of true, which means that only the location xx/y/zz is considered + // as possibly being a source of emissive light, not other tiles that we might encounter whilst propagating the light from + // the start location. If we don't do this, and Do encounter another emissive source in the radius of influence that the first + // light source had, then we'll start also lighting from that tile but won't actually be able to progatate that second light + // fully since checkLight only has a finite radius of 17 from the start position that it can light. Then when we do a checkLight + // on the second light later, it won't bother doing anything because the light level at the location of the tile itself will be correct. + chunk->level->checkLight(LightLayer::Block, xx, y, zz, true, true); + } + } + + return blocksIncluded; +} + +void ConsoleSchematicFile::chunkCoordToSchematicCoord(AABB *destinationBox, int chunkX, int chunkZ, ESchematicRotation rot, int &schematicX, int &schematicZ) +{ + switch(rot) + { + case eSchematicRot_90: + // schematicX decreases as chunkZ increases + // schematicZ increases as chunkX increases + schematicX = chunkZ - destinationBox->z0; + schematicZ = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); + break; + case eSchematicRot_180: + // schematicX decreases as chunkX increases + // schematicZ decreases as chunkZ increases + schematicX = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); + schematicZ = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); + break; + case eSchematicRot_270: + // schematicX increases as chunkZ increases + // shcematicZ decreases as chunkX increases + schematicX = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); + schematicZ = chunkX - destinationBox->x0; + break; + case eSchematicRot_0: + default: + // schematicX increases as chunkX increases + // schematicZ increases as chunkZ increases + schematicX = chunkX - destinationBox->x0; + schematicZ = chunkZ - destinationBox->z0; + break; + }; +} + +void ConsoleSchematicFile::schematicCoordToChunkCoord(AABB *destinationBox, double schematicX, double schematicZ, ESchematicRotation rot, double &chunkX, double &chunkZ) +{ + switch(rot) + { + case eSchematicRot_90: + // schematicX decreases as chunkZ increases + // schematicZ increases as chunkX increases + chunkX = (destinationBox->x1 - 1 - schematicZ); + chunkZ = schematicX + destinationBox->z0; + break; + case eSchematicRot_180: + // schematicX decreases as chunkX increases + // schematicZ decreases as chunkZ increases + chunkX = (destinationBox->x1 - 1 - schematicX); + chunkZ = (destinationBox->z1 - 1 - schematicZ); + break; + case eSchematicRot_270: + // schematicX increases as chunkZ increases + // shcematicZ decreases as chunkX increases + chunkX = schematicZ + destinationBox->x0; + chunkZ = (destinationBox->z1 - 1 - schematicX); + break; + case eSchematicRot_0: + default: + // schematicX increases as chunkX increases + // schematicZ increases as chunkZ increases + chunkX = schematicX + destinationBox->x0; + chunkZ = schematicZ + destinationBox->z0; + break; + }; +} + +void ConsoleSchematicFile::applyTileEntities(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + for(AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end();++it) + { + shared_ptr<TileEntity> te = *it; + + double targetX = te->x; + double targetY = te->y + destinationBox->y0; + double targetZ = te->z; + + schematicCoordToChunkCoord(destinationBox, te->x, te->z, rot, targetX, targetZ); + + Vec3 *pos = Vec3::newTemp(targetX,targetY,targetZ); + if( chunkBox->containsIncludingLowerBound(pos) ) + { + shared_ptr<TileEntity> teCopy = chunk->getTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 ); + + if ( teCopy != NULL ) + { + CompoundTag *teData = new CompoundTag(); + te->save(teData); + + teCopy->load(teData); + + delete teData; + + // Adjust the tileEntity position to world coords from schematic co-ords + teCopy->x = targetX; + teCopy->y = targetY; + teCopy->z = targetZ; + + // Remove the current tile entity + //chunk->removeTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 ); + } + else + { + teCopy = te->clone(); + + // Adjust the tileEntity position to world coords from schematic co-ords + teCopy->x = targetX; + teCopy->y = targetY; + teCopy->z = targetZ; + chunk->addTileEntity(teCopy); + } + + teCopy->setChanged(); + } + } + for(AUTO_VAR(it, m_entities.begin()); it != m_entities.end();) + { + Vec3 *source = it->first; + + double targetX = source->x; + double targetY = source->y + destinationBox->y0; + double targetZ = source->z; + schematicCoordToChunkCoord(destinationBox, source->x, source->z, rot, targetX, targetZ); + + // Add 0.01 as the AABB::contains function returns false if a value is <= the lower bound + Vec3 *pos = Vec3::newTemp(targetX+0.01,targetY+0.01,targetZ+0.01); + if( !chunkBox->containsIncludingLowerBound(pos) ) + { + ++it; + continue; + } + + CompoundTag *eTag = it->second; + shared_ptr<Entity> e = EntityIO::loadStatic(eTag, NULL); + + if( e->GetType() == eTYPE_PAINTING ) + { + shared_ptr<Painting> painting = dynamic_pointer_cast<Painting>(e); + + double tileX = painting->xTile; + double tileZ = painting->zTile; + schematicCoordToChunkCoord(destinationBox, painting->xTile, painting->zTile, rot, tileX, tileZ); + + painting->yTile += destinationBox->y0; + painting->xTile = tileX; + painting->zTile = tileZ; + painting->setDir(painting->dir); + } + else if( e->GetType() == eTYPE_ITEM_FRAME ) + { + shared_ptr<ItemFrame> frame = dynamic_pointer_cast<ItemFrame>(e); + + double tileX = frame->xTile; + double tileZ = frame->zTile; + schematicCoordToChunkCoord(destinationBox, frame->xTile, frame->zTile, rot, tileX, tileZ); + + frame->yTile += destinationBox->y0; + frame->xTile = tileX; + frame->zTile = tileZ; + frame->setDir(frame->dir); + } + else + { + e->absMoveTo(targetX, targetY, targetZ,e->yRot,e->xRot); + } +#ifdef _DEBUG + app.DebugPrintf("Adding entity type %d at (%f,%f,%f)\n",e->GetType(),e->x,e->y,e->z); +#endif + e->setLevel(chunk->level); + e->resetSmallId(); + e->setDespawnProtected(); // default to being protected against despawning + chunk->level->addEntity(e); + + // 4J Stu - Until we can copy every type of entity, remove them from this vector + // This means that the entities will only exist in the first use of the schematic that is processed + //it = m_entities.erase(it); + ++it; + } +} + +void ConsoleSchematicFile::generateSchematicFile(DataOutputStream *dos, Level *level, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, bool bSaveMobs, Compression::ECompressionTypes compressionType) +{ + assert(xEnd > xStart); + assert(yEnd > yStart); + assert(zEnd > zStart); + // 4J Stu - Enforce even numbered positions to start with to avoid problems with half-bytes in data + + // We want the start to be even + if(xStart > 0 && xStart%2 != 0) + xStart-=1; + else if(xStart < 0 && xStart%2 !=0) + xStart-=1; + if(yStart < 0) yStart = 0; + else if(yStart > 0 && yStart%2 != 0) + yStart-=1; + if(zStart > 0 && zStart%2 != 0) + zStart-=1; + else if(zStart < 0 && zStart%2 !=0) + zStart-=1; + + // We want the end to be odd to have a total size that is even + if(xEnd > 0 && xEnd%2 == 0) + xEnd+=1; + else if(xEnd < 0 && xEnd%2 ==0) + xEnd+=1; + if(yEnd > Level::maxBuildHeight) + yEnd = Level::maxBuildHeight; + else if(yEnd > 0 && yEnd%2 == 0) + yEnd+=1; + else if(yEnd < 0 && yEnd%2 ==0) + yEnd+=1; + if(zEnd > 0 && zEnd%2 == 0) + zEnd+=1; + else if(zEnd < 0 && zEnd%2 ==0) + zEnd+=1; + + int xSize = xEnd - xStart + 1; + int ySize = yEnd - yStart + 1; + int zSize = zEnd - zStart + 1; + + app.DebugPrintf("Generating schematic file for area (%d,%d,%d) to (%d,%d,%d), %dx%dx%d\n",xStart,yStart,zStart,xEnd,yEnd,zEnd,xSize,ySize,zSize); + + if(dos != NULL) dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION); + + if(dos != NULL) dos->writeByte(compressionType); + + //Write xSize + if(dos != NULL) dos->writeInt(xSize); + + //Write ySize + if(dos != NULL) dos->writeInt(ySize); + + //Write zSize + if(dos != NULL) dos->writeInt(zSize); + + //byteArray rawBuffer = level->getBlocksAndData(xStart, yStart, zStart, xSize, ySize, zSize, false); + int xRowSize = ySize * zSize; + int blockCount = xSize * xRowSize; + byteArray result( blockCount * 3 / 2 ); + + // Position pointers into the data when not ordered by chunk + int p = 0; + int dataP = blockCount; + int blockLightP = -1; + int skyLightP = -1; + + int y0 = yStart; + int y1 = yStart + ySize; + if (y0 < 0) y0 = 0; + if (y1 > Level::maxBuildHeight) y1 = Level::maxBuildHeight; + + // Every x is a whole row + for(int xPos = xStart; xPos < xStart + xSize; ++xPos) + { + int xc = xPos >> 4; + + int x0 = xPos - xc * 16; + if (x0 < 0) x0 = 0; + int x1 = x0 + 1; + if (x1 > 16) x1 = 16; + + for(int zPos = zStart; zPos < zStart + zSize;) + { + int zc = zPos >> 4; + + int z0 = zStart - zc * 16; + int z1 = zStart + zSize - zc * 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; + getBlocksAndData(level->getChunk(xc, zc), &result, x0, y0, z0, x1, y1, z1, p, dataP, blockLightP, skyLightP); + zPos += (z1-z0); + } + } + +#ifndef _CONTENT_PACKAGE + if(p!=blockCount) __debugbreak(); +#endif + + // We don't know how this will compress - just make a fixed length buffer to initially decompress into + // Some small sets of blocks can end up compressing into something bigger than their source + unsigned int inputSize = blockCount * 3 / 2; + unsigned char *ucTemp = new unsigned char[inputSize]; + + switch(compressionType) + { + case Compression::eCompressionType_LZXRLE: + Compression::getCompression()->CompressLZXRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); + break; + case Compression::eCompressionType_RLE: + Compression::getCompression()->CompressRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); + break; + case Compression::eCompressionType_None: + default: + memcpy( ucTemp, result.data, inputSize ); + break; + }; + + delete [] result.data; + byteArray buffer = byteArray(ucTemp,inputSize); + + if(dos != NULL) dos->writeInt(inputSize); + if(dos != NULL) dos->write(buffer); + delete [] buffer.data; + + CompoundTag tag; + ListTag<CompoundTag> *tileEntitiesTag = new ListTag<CompoundTag>(L"tileEntities"); + + int xc0 = xStart >> 4; + int zc0 = zStart >> 4; + int xc1 = (xStart + xSize - 1) >> 4; + int zc1 = (zStart + zSize - 1) >> 4; + + for (int xc = xc0; xc <= xc1; xc++) + { + for (int zc = zc0; zc <= zc1; zc++) + { + vector<shared_ptr<TileEntity> > *tileEntities = getTileEntitiesInRegion(level->getChunk(xc, zc), xStart, yStart, zStart, xStart + xSize, yStart + ySize, zStart + zSize); + for(AUTO_VAR(it, tileEntities->begin()); it != tileEntities->end(); ++it) + { + shared_ptr<TileEntity> te = *it; + CompoundTag *teTag = new CompoundTag(); + shared_ptr<TileEntity> teCopy = te->clone(); + + // Adjust the tileEntity position to schematic coords from world co-ords + teCopy->x -= xStart; + teCopy->y -= yStart; + teCopy->z -= zStart; + teCopy->save(teTag); + tileEntitiesTag->add(teTag); + } + delete tileEntities; + } + } + tag.put(L"TileEntities", tileEntitiesTag); + + AABB *bb = AABB::newTemp(xStart,yStart,zStart,xEnd,yEnd,zEnd); + vector<shared_ptr<Entity> > *entities = level->getEntities(nullptr, bb); + ListTag<CompoundTag> *entitiesTag = new ListTag<CompoundTag>(L"entities"); + + for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) + { + shared_ptr<Entity> e = *it; + + bool mobCanBeSaved = false; + if(bSaveMobs) + { + if( ( e->GetType() & eTYPE_MONSTER ) || ( e->GetType() & eTYPE_WATERANIMAL ) || ( e->GetType() & eTYPE_ANIMAL ) || + ( e->GetType() == eTYPE_CHICKEN ) || ( e->GetType() == eTYPE_WOLF ) || ( e->GetType() == eTYPE_VILLAGER) || ( e->GetType() == eTYPE_MUSHROOMCOW ) ) + { + mobCanBeSaved = true; + } + } + if(mobCanBeSaved || e->GetType() == eTYPE_MINECART || e->GetType() == eTYPE_BOAT || e->GetType() == eTYPE_PAINTING || e->GetType() == eTYPE_ITEM_FRAME) + { + CompoundTag *eTag = new CompoundTag(); + if( e->save(eTag) ) + { + ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) eTag->getList(L"Pos"); + + pos->get(0)->data -= xStart; + pos->get(1)->data -= yStart; + pos->get(2)->data -= zStart; + + if( e->GetType() == eTYPE_PAINTING || e->GetType() == eTYPE_ITEM_FRAME ) + { + ((IntTag *) eTag->get(L"TileX") )->data -= xStart; + ((IntTag *) eTag->get(L"TileY") )->data -= yStart; + ((IntTag *) eTag->get(L"TileZ") )->data -= zStart; + } + + entitiesTag->add(eTag); + } + } + } + + tag.put(L"Entities", entitiesTag); + + if(dos != NULL) NbtIo::write(&tag,dos); +} + +void ConsoleSchematicFile::getBlocksAndData(LevelChunk *chunk, byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP) +{ + // 4J Stu - Needs updated to work with higher worlds, should still work with non-optimised version below + //int xs = x1 - x0; + //int ys = y1 - y0; + //int zs = z1 - z0; + //if (xs * ys * zs == LevelChunk::BLOCKS_LENGTH) + //{ + // byteArray blockData = byteArray(data->data + blocksP, Level::CHUNK_TILE_COUNT); + // chunk->getBlockData(blockData); + // blocksP += blockData.length; + + // byteArray dataData = byteArray(data->data + dataP, 16384); + // chunk->getBlockLightData(dataData); + // dataP += dataData.length; + + // byteArray blockLightData = byteArray(data->data + blockLightP, 16384); + // chunk->getBlockLightData(blockLightData); + // blockLightP += blockLightData.length; + + // byteArray skyLightData = byteArray(data->data + skyLightP, 16384); + // chunk->getSkyLightData(skyLightData); + // skyLightP += skyLightData.length; + // return; + //} + + bool bHasLower, bHasUpper; + bHasLower = bHasUpper = false; + int lowerY0, lowerY1, upperY0, upperY1; + lowerY0 = upperY0 = y0; + lowerY1 = upperY1 = y1; + + int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + lowerY0 = y0; + lowerY1 = min(y1, compressedHeight); + bHasLower = true; + } + if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + bHasUpper = true; + } + + byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); + chunk->getBlockData(blockData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; + int len = lowerY1 - lowerY0; + System::arraycopy(blockData, slot, data, blocksP, len); + blocksP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; + int len = upperY1 - upperY0; + System::arraycopy(blockData, slot, data, blocksP, len); + blocksP += len; + } + } + delete blockData.data; + + byteArray dataData = byteArray(Level::CHUNK_TILE_COUNT); + chunk->getDataData(dataData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(dataData, slot, data, dataP, len); + dataP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; + int len = (upperY1 - upperY0) / 2; + System::arraycopy(dataData, slot, data, dataP, len); + dataP += len; + } + } + delete dataData.data; + + // 4J Stu - Allow ignoring light data + if(blockLightP > -1) + { + byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getBlockLightData(blockLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(blockLightData, slot, data, blockLightP, len); + blockLightP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(blockLightData, slot, data, blockLightP, len); + blockLightP += len; + } + } + delete blockLightData.data; + } + + + // 4J Stu - Allow ignoring light data + if(skyLightP > -1) + { + byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getSkyLightData(skyLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(skyLightData, slot, data, skyLightP, len); + skyLightP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(skyLightData, slot, data, skyLightP, len); + skyLightP += len; + } + } + delete skyLightData.data; + } + + return; +} + +void ConsoleSchematicFile::setBlocksAndData(LevelChunk *chunk, byteArray blockData, byteArray dataData, byteArray inputData, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP) +{ + bool bHasLower, bHasUpper; + bHasLower = bHasUpper = false; + int lowerY0, lowerY1, upperY0, upperY1; + lowerY0 = upperY0 = y0; + lowerY1 = upperY1 = y1; + + int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + lowerY0 = y0; + lowerY1 = min(y1, compressedHeight); + bHasLower = true; + } + if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + bHasUpper = true; + } + PIXBeginNamedEvent(0,"Applying block data"); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; + int len = lowerY1 - lowerY0; + System::arraycopy(inputData, blocksP, &blockData, slot, len); + blocksP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; + int len = upperY1 - upperY0; + System::arraycopy(inputData, blocksP, &blockData, slot, len); + blocksP += len; + } + } + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Applying Data data"); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, dataP, &dataData, slot, len); + dataP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, dataP, &dataData, slot, len); + dataP += len; + } + } + PIXEndNamedEvent(); + // 4J Stu - Allow ignoring light data + if(blockLightP > -1) + { + byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getBlockLightData(blockLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); + blockLightP += len; + } + if(bHasUpper) + { + int slot = ( (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); + blockLightP += len; + } + } + chunk->setBlockLightData(blockLightData); + delete blockLightData.data; + } + + // 4J Stu - Allow ignoring light data + if(skyLightP > -1) + { + byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getSkyLightData(skyLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); + skyLightP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); + skyLightP += len; + } + } + chunk->setSkyLightData(skyLightData); + delete skyLightData.data; + } +} + +vector<shared_ptr<TileEntity> > *ConsoleSchematicFile::getTileEntitiesInRegion(LevelChunk *chunk, int x0, int y0, int z0, int x1, int y1, int z1) +{ + vector<shared_ptr<TileEntity> > *result = new vector<shared_ptr<TileEntity> >; + for (AUTO_VAR(it, chunk->tileEntities.begin()); it != chunk->tileEntities.end(); ++it) + { + shared_ptr<TileEntity> te = it->second; + if (te->x >= x0 && te->y >= y0 && te->z >= z0 && te->x < x1 && te->y < y1 && te->z < z1) + { + result->push_back(te); + } + } + return result; +} diff --git a/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h new file mode 100644 index 00000000..f37a6058 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h @@ -0,0 +1,90 @@ +#pragma once +using namespace std; + +#define XBOX_SCHEMATIC_ORIGINAL_VERSION 1 +#define XBOX_SCHEMATIC_CURRENT_VERSION 2 + +#include "..\..\..\Minecraft.World\ArrayWithLength.h" + +class Level; +class DataOutputStream; +class DataInputStream; +class TileEntity; +class LevelChunk; +class AABB; +class Vec3; + +class ConsoleSchematicFile +{ +public: + enum ESchematicRotation + { + eSchematicRot_0, + eSchematicRot_90, + eSchematicRot_180, + eSchematicRot_270 + }; +private: + int m_refCount; + +public: + void incrementRefCount() { ++m_refCount; } + void decrementRefCount() { --m_refCount; } + bool shouldDelete() { return m_refCount <= 0; } + + typedef struct _XboxSchematicInitParam + { + wchar_t name[64]; + int startX; + int startY; + int startZ; + int endX; + int endY; + int endZ; + bool bSaveMobs; + + Compression::ECompressionTypes compressionType; + + _XboxSchematicInitParam() + { + ZeroMemory(name,64*(sizeof(wchar_t))); + startX = startY = startZ = endX = endY = endZ = 0; + bSaveMobs = false; + compressionType = Compression::eCompressionType_None; + } + } XboxSchematicInitParam; +private: + int m_xSize, m_ySize, m_zSize; + vector<shared_ptr<TileEntity> > m_tileEntities; + vector< pair<Vec3 *, CompoundTag *> > m_entities; + +public: + byteArray m_data; + +public: + ConsoleSchematicFile(); + ~ConsoleSchematicFile(); + + int getXSize() { return m_xSize; } + int getYSize() { return m_ySize; } + int getZSize() { return m_zSize; } + + void save(DataOutputStream *dos); + void load(DataInputStream *dis); + + __int64 applyBlocksAndData(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + __int64 applyLighting(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + void applyTileEntities(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + + static void generateSchematicFile(DataOutputStream *dos, Level *level, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, bool bSaveMobs, Compression::ECompressionTypes); + static void setBlocksAndData(LevelChunk *chunk, byteArray blockData, byteArray dataData, byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP); +private: + void save_tags(DataOutputStream *dos); + void load_tags(DataInputStream *dis); + + static void getBlocksAndData(LevelChunk *chunk, byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP); + static vector<shared_ptr<TileEntity> > *getTileEntitiesInRegion(LevelChunk *chunk, int x0, int y0, int z0, int x1, int y1, int z1); + + void chunkCoordToSchematicCoord(AABB *destinationBox, int chunkX, int chunkZ, ESchematicRotation rot, int &schematicX, int &schematicZ); + void schematicCoordToChunkCoord(AABB *destinationBox, double schematicX, double schematicZ, ESchematicRotation rot, double &chunkX, double &chunkZ); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRule.cpp b/Minecraft.Client/Common/GameRules/GameRule.cpp new file mode 100644 index 00000000..34d6196c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRule.cpp @@ -0,0 +1,97 @@ +#include "stdafx.h" +#include "ConsoleGameRules.h" + +GameRule::GameRule(GameRuleDefinition *definition, Connection *connection) +{ + m_definition = definition; + m_connection = connection; +} + +GameRule::~GameRule() +{ + for(AUTO_VAR(it, m_parameters.begin()); it != m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + delete it->second.gr; + } + } +} + +GameRule::ValueType GameRule::getParameter(const wstring ¶meterName) +{ + if(m_parameters.find(parameterName) == m_parameters.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"WARNING: Parameter %ls was not set before being fetched\n", parameterName.c_str()); + __debugbreak(); +#endif + } + return m_parameters[parameterName]; +} + +void GameRule::setParameter(const wstring ¶meterName,ValueType value) +{ + if(m_parameters.find(parameterName) == m_parameters.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Adding parameter %ls to GameRule\n", parameterName.c_str()); +#endif + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Setting parameter %ls for GameRule\n", parameterName.c_str()); +#endif + } + m_parameters[parameterName] = value; +} + +GameRuleDefinition *GameRule::getGameRuleDefinition() +{ + return m_definition; +} + +void GameRule::onUseTile(int tileId, int x, int y, int z) { m_definition->onUseTile(this,tileId,x,y,z); } +void GameRule::onCollectItem(shared_ptr<ItemInstance> item) { m_definition->onCollectItem(this,item); } + +void GameRule::write(DataOutputStream *dos) +{ + // Find required parameters. + dos->writeInt(m_parameters.size()); + for (AUTO_VAR(it, m_parameters.begin()); it != m_parameters.end(); it++) + { + wstring pName = (*it).first; + ValueType vType = (*it).second; + + dos->writeUTF( (*it).first ); + dos->writeBoolean( vType.isPointer ); + + if (vType.isPointer) + vType.gr->write(dos); + else + dos->writeLong( vType.i64 ); + } +} + +void GameRule::read(DataInputStream *dis) +{ + int savedParams = dis->readInt(); + for (int i = 0; i < savedParams; i++) + { + wstring pNames = dis->readUTF(); + + ValueType vType = getParameter(pNames); + + if (dis->readBoolean()) + { + vType.gr->read(dis); + } + else + { + vType.isPointer = false; + vType.i64 = dis->readLong(); + setParameter(pNames, vType); + } + } +} diff --git a/Minecraft.Client/Common/GameRules/GameRule.h b/Minecraft.Client/Common/GameRules/GameRule.h new file mode 100644 index 00000000..bdc2ceff --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRule.h @@ -0,0 +1,62 @@ +#pragma once +using namespace std; + +#include <unordered_map> + +class CompoundTag; +class GameRuleDefinition; +class Connection; + +// A game rule maintains the state for one particular definition +class GameRule +{ +public: + typedef struct _ValueType + { + union{ + __int64 i64; + int i; + char c; + bool b; + float f; + double d; + GameRule *gr; + }; + bool isPointer; + + _ValueType() + { + i64 = 0; + isPointer = false; + } + } ValueType; + +private: + GameRuleDefinition *m_definition; + Connection *m_connection; + +public: + typedef unordered_map<wstring,ValueType> stringValueMapType; + stringValueMapType m_parameters; // These are the members of this rule that maintain it's state + +public: + GameRule(GameRuleDefinition *definition, Connection *connection = NULL); + virtual ~GameRule(); + + Connection *getConnection() { return m_connection; } + + ValueType getParameter(const wstring ¶meterName); + void setParameter(const wstring ¶meterName,ValueType value); + GameRuleDefinition *getGameRuleDefinition(); + + // All the hooks go here + void onUseTile(int tileId, int x, int y, int z); + void onCollectItem(shared_ptr<ItemInstance> item); + + // 4J-JEV: For saving. + //CompoundTag *toTags(unordered_map<GameRuleDefinition *, int> *map); + //static GameRule *fromTags(Connection *c, CompoundTag *cTag, vector<GameRuleDefinition *> *grds); + + void write(DataOutputStream *dos); + void read(DataInputStream *dos); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp new file mode 100644 index 00000000..b63687c2 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp @@ -0,0 +1,151 @@ +#include "stdafx.h" +#include "..\..\WstringLookup.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "ConsoleGameRules.h" + +GameRuleDefinition::GameRuleDefinition() +{ + m_descriptionId = L""; + m_promptId = L""; + m_4JDataValue = 0; +} + +void GameRuleDefinition::write(DataOutputStream *dos) +{ + // Write EGameRuleType. + ConsoleGameRules::EGameRuleType eType = getActionType(); + assert( eType != ConsoleGameRules::eGameRuleType_Invalid ); + ConsoleGameRules::write(dos, eType); // stringID + + writeAttributes(dos, 0); + + // 4J-JEV: Get children. + vector<GameRuleDefinition *> *children = new vector<GameRuleDefinition *>(); + getChildren( children ); + + // Write children. + dos->writeInt( children->size() ); + for (AUTO_VAR(it, children->begin()); it != children->end(); it++) + (*it)->write(dos); +} + +void GameRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + dos->writeInt(numAttributes + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_descriptionName); + dos->writeUTF(m_descriptionId); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_promptName); + dos->writeUTF(m_promptId); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dataTag); + dos->writeUTF(_toString(m_4JDataValue)); +} + +void GameRuleDefinition::getChildren(vector<GameRuleDefinition *> *children) {} + +GameRuleDefinition *GameRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + return NULL; +} + +void GameRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"descriptionName") == 0) + { + m_descriptionId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Adding parameter descriptionId=%ls\n",m_descriptionId.c_str()); +#endif + } + else if(attributeName.compare(L"promptName") == 0) + { + m_promptId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Adding parameter m_promptId=%ls\n",m_promptId.c_str()); +#endif + } + else if(attributeName.compare(L"dataTag") == 0) + { + m_4JDataValue = _fromString<int>(attributeValue); + app.DebugPrintf("GameRuleDefinition: Adding parameter m_4JDataValue=%d\n",m_4JDataValue); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Attempted to add invalid attribute: %ls\n", attributeName.c_str()); +#endif + } +} + +void GameRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule::ValueType value; + value.b = false; + rule->setParameter(L"bComplete",value); +} + +bool GameRuleDefinition::getComplete(GameRule *rule) +{ + GameRule::ValueType value; + value = rule->getParameter(L"bComplete"); + return value.b; +} + +void GameRuleDefinition::setComplete(GameRule *rule, bool val) +{ + GameRule::ValueType value; + value = rule->getParameter(L"bComplete"); + value.b = val; + rule->setParameter(L"bComplete",value); +} + +vector<GameRuleDefinition *> *GameRuleDefinition::enumerate() +{ + // Get Vector. + vector<GameRuleDefinition *> *gRules; + gRules = new vector<GameRuleDefinition *>(); + gRules->push_back(this); + getChildren(gRules); + return gRules; +} + +unordered_map<GameRuleDefinition *, int> *GameRuleDefinition::enumerateMap() +{ + unordered_map<GameRuleDefinition *, int> *out + = new unordered_map<GameRuleDefinition *, int>(); + + int i = 0; + vector<GameRuleDefinition *> *gRules = enumerate(); + for (AUTO_VAR(it, gRules->begin()); it != gRules->end(); it++) + out->insert( pair<GameRuleDefinition *, int>( *it, i++ ) ); + + return out; +} + +GameRulesInstance *GameRuleDefinition::generateNewGameRulesInstance(GameRulesInstance::EGameRulesInstanceType type, LevelRuleset *rules, Connection *connection) +{ + GameRulesInstance *manager = new GameRulesInstance(rules, connection); + + rules->populateGameRule(type, manager); + + return manager; +} + +wstring GameRuleDefinition::generateDescriptionString(ConsoleGameRules::EGameRuleType defType, const wstring &description, void *data, int dataLength) +{ + wstring formatted = description; + switch(defType) + { + case ConsoleGameRules::eGameRuleType_CompleteAllRule: + formatted = CompleteAllRuleDefinition::generateDescriptionString(description,data,dataLength); + break; + default: + break; + }; + return formatted; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleDefinition.h b/Minecraft.Client/Common/GameRules/GameRuleDefinition.h new file mode 100644 index 00000000..afec8fbc --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleDefinition.h @@ -0,0 +1,66 @@ +#pragma once +using namespace std; +#include <unordered_map> +#include <string> + +#include "..\..\..\Minecraft.World\ItemInstance.h" +#include "ConsoleGameRulesConstants.h" + +#include "GameRulesInstance.h" + +class GameRule; +class LevelRuleset; +class Player; +class WstringLookup; + +class GameRuleDefinition +{ +private: + // Owner type defines who this rule applies to + GameRulesInstance::EGameRulesInstanceType m_ownerType; + +protected: + // These attributes should map to those in the XSD GameRuleType + wstring m_descriptionId; + wstring m_promptId; + int m_4JDataValue; + +public: + GameRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() = 0; + + void setOwnerType(GameRulesInstance::EGameRulesInstanceType ownerType) { m_ownerType = ownerType;} + + virtual void write(DataOutputStream *); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void getChildren(vector<GameRuleDefinition *> *); + + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + bool getComplete(GameRule *rule); + void setComplete(GameRule *rule, bool val); + + virtual int getGoal() { return 0; } + virtual int getProgress(GameRule *rule) { return 0; } + + virtual int getIcon() { return -1; } + virtual int getAuxValue() { return 0; } + + // Here we should have functions for all the hooks, with a GameRule* as the first parameter + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z) { return false; } + virtual bool onCollectItem(GameRule *rule, shared_ptr<ItemInstance> item) { return false; } + virtual void postProcessPlayer(shared_ptr<Player> player) { } + + vector<GameRuleDefinition *> *enumerate(); + unordered_map<GameRuleDefinition *, int> *enumerateMap(); + + // Static functions + static GameRulesInstance *generateNewGameRulesInstance(GameRulesInstance::EGameRulesInstanceType type, LevelRuleset *rules, Connection *connection); + static wstring generateDescriptionString(ConsoleGameRules::EGameRuleType defType, const wstring &description, void *data = NULL, int dataLength = 0); + +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleManager.cpp b/Minecraft.Client/Common/GameRules/GameRuleManager.cpp new file mode 100644 index 00000000..0c6a7804 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleManager.cpp @@ -0,0 +1,767 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\File.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\DLC\DLCPack.h" +#include "..\DLC\DLCLocalisationFile.h" +#include "..\DLC\DLCGameRulesFile.h" +#include "..\DLC\DLCGameRules.h" +#include "..\DLC\DLCGameRulesHeader.h" +#include "..\..\StringTable.h" +#include "ConsoleGameRules.h" +#include "GameRuleManager.h" + +WCHAR *GameRuleManager::wchTagNameA[] = +{ + L"", // eGameRuleType_Root + L"MapOptions", // eGameRuleType_LevelGenerationOptions + L"ApplySchematic", // eGameRuleType_ApplySchematic + L"GenerateStructure", // eGameRuleType_GenerateStructure + L"GenerateBox", // eGameRuleType_GenerateBox + L"PlaceBlock", // eGameRuleType_PlaceBlock + L"PlaceContainer", // eGameRuleType_PlaceContainer + L"PlaceSpawner", // eGameRuleType_PlaceSpawner + L"BiomeOverride", // eGameRuleType_BiomeOverride + L"StartFeature", // eGameRuleType_StartFeature + L"AddItem", // eGameRuleType_AddItem + L"AddEnchantment", // eGameRuleType_AddEnchantment + L"LevelRules", // eGameRuleType_LevelRules + L"NamedArea", // eGameRuleType_NamedArea + L"UseTile", // eGameRuleType_UseTileRule + L"CollectItem", // eGameRuleType_CollectItemRule + L"CompleteAll", // eGameRuleType_CompleteAllRule + L"UpdatePlayer", // eGameRuleType_UpdatePlayerRule +}; + +WCHAR *GameRuleManager::wchAttrNameA[] = +{ + L"descriptionName", // eGameRuleAttr_descriptionName + L"promptName", // eGameRuleAttr_promptName + L"dataTag", // eGameRuleAttr_dataTag + L"enchantmentId", // eGameRuleAttr_enchantmentId + L"enchantmentLevel", // eGameRuleAttr_enchantmentLevel + L"itemId", // eGameRuleAttr_itemId + L"quantity", // eGameRuleAttr_quantity + L"auxValue", // eGameRuleAttr_auxValue + L"slot", // eGameRuleAttr_slot + L"name", // eGameRuleAttr_name + L"food", // eGameRuleAttr_food + L"health", // eGameRuleAttr_health + L"tileId", // eGameRuleAttr_tileId + L"useCoords", // eGameRuleAttr_useCoords + L"seed", // eGameRuleAttr_seed + L"flatworld", // eGameRuleAttr_flatworld + L"filename", // eGameRuleAttr_filename + L"rot", // eGameRuleAttr_rot + L"data", // eGameRuleAttr_data + L"block", // eGameRuleAttr_block + L"entity", // eGameRuleAttr_entity + L"facing", // eGameRuleAttr_facing + L"edgeTile", // eGameRuleAttr_edgeTile + L"fillTile", // eGameRuleAttr_fillTile + L"skipAir", // eGameRuleAttr_skipAir + L"x", // eGameRuleAttr_x + L"x0", // eGameRuleAttr_x0 + L"x1", // eGameRuleAttr_x1 + L"y", // eGameRuleAttr_y + L"y0", // eGameRuleAttr_y0 + L"y1", // eGameRuleAttr_y1 + L"z", // eGameRuleAttr_z + L"z0", // eGameRuleAttr_z0 + L"z1", // eGameRuleAttr_z1 + L"chunkX", // eGameRuleAttr_chunkX + L"chunkZ", // eGameRuleAttr_chunkZ + L"yRot", // eGameRuleAttr_yRot + L"spawnX", // eGameRuleAttr_spawnX + L"spawnY", // eGameRuleAttr_spawnY + L"spawnZ", // eGameRuleAttr_spawnZ + L"orientation", + L"dimension", + L"topTileId", // eGameRuleAttr_topTileId + L"biomeId", // eGameRuleAttr_biomeId + L"feature", // eGameRuleAttr_feature +}; + +GameRuleManager::GameRuleManager() +{ + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = NULL; +} + +void GameRuleManager::loadGameRules(DLCPack *pack) +{ + StringTable *strings = NULL; + + if(pack->doesPackContainFile(DLCManager::e_DLCType_LocalisationData,L"languages.loc")) + { + DLCLocalisationFile *localisationFile = (DLCLocalisationFile *)pack->getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"); + strings = localisationFile->getStringTable(); + } + + int gameRulesCount = pack->getDLCItemsCount(DLCManager::e_DLCType_GameRulesHeader); + for(int i = 0; i < gameRulesCount; ++i) + { + DLCGameRulesHeader *dlcHeader = (DLCGameRulesHeader *)pack->getFile(DLCManager::e_DLCType_GameRulesHeader, i); + DWORD dSize; + byte *dData = dlcHeader->getData(dSize); + + LevelGenerationOptions *createdLevelGenerationOptions = new LevelGenerationOptions(); + // = loadGameRules(dData, dSize); //, strings); + + createdLevelGenerationOptions->setGrSource( dlcHeader ); + + readRuleFile(createdLevelGenerationOptions, dData, dSize, strings); + + createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_fromDLC ); + + + //createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_fromDLC ); + dlcHeader->lgo = createdLevelGenerationOptions; + } + + gameRulesCount = pack->getDLCItemsCount(DLCManager::e_DLCType_GameRules); + for (int i = 0; i < gameRulesCount; ++i) + { + DLCGameRulesFile *dlcFile = (DLCGameRulesFile *)pack->getFile(DLCManager::e_DLCType_GameRules, i); + + DWORD dSize; + byte *dData = dlcFile->getData(dSize); + + LevelGenerationOptions *createdLevelGenerationOptions = new LevelGenerationOptions(); + // = loadGameRules(dData, dSize); //, strings); + + createdLevelGenerationOptions->setGrSource( new JustGrSource() ); + readRuleFile(createdLevelGenerationOptions, dData, dSize, strings); + + createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_tutorial ); + + //createdLevelGenerationOptions->set_DLCGameRulesFile( dlcFile ); + + createdLevelGenerationOptions->setLoadedData(); + } +} + +LevelGenerationOptions *GameRuleManager::loadGameRules(byte *dIn, UINT dSize) +{ + LevelGenerationOptions *lgo = new LevelGenerationOptions(); + lgo->setGrSource( new JustGrSource() ); + lgo->setSrc( LevelGenerationOptions::eSrc_fromSave ); + loadGameRules(lgo, dIn, dSize); + lgo->setLoadedData(); + return lgo; +} + +// 4J-JEV: Reverse of saveGameRules. +void GameRuleManager::loadGameRules(LevelGenerationOptions *lgo, byte *dIn, UINT dSize) +{ + app.DebugPrintf("GameRuleManager::LoadingGameRules:\n"); + + ByteArrayInputStream bais( byteArray(dIn,dSize) ); + DataInputStream dis(&bais); + + // Read file header. + + //dis.readInt(); // File Size + + short version = dis.readShort(); + assert( 0x1 == version ); + app.DebugPrintf("\tversion=%d.\n", version); + + for (int i = 0; i < 8; i++) dis.readByte(); + + BYTE compression_type = dis.readByte(); + + app.DebugPrintf("\tcompressionType=%d.\n", compression_type); + + UINT compr_len, decomp_len; + compr_len = dis.readInt(); + decomp_len = dis.readInt(); + + app.DebugPrintf("\tcompr_len=%d.\n\tdecomp_len=%d.\n", compr_len, decomp_len); + + + // Decompress File Body + + byteArray content(new BYTE[decomp_len], decomp_len), + compr_content(new BYTE[compr_len], compr_len); + dis.read(compr_content); + + Compression::getCompression()->SetDecompressionType( (Compression::ECompressionTypes)compression_type ); + Compression::getCompression()->DecompressLZXRLE( content.data, &content.length, + compr_content.data, compr_content.length); + Compression::getCompression()->SetDecompressionType( SAVE_FILE_PLATFORM_LOCAL ); + + dis.close(); + bais.close(); + + delete [] compr_content.data; + + ByteArrayInputStream bais2( content ); + DataInputStream dis2( &bais2 ); + + // Read StringTable. + byteArray bStringTable; + bStringTable.length = dis2.readInt(); + bStringTable.data = new BYTE[ bStringTable.length ]; + dis2.read(bStringTable); + StringTable *strings = new StringTable(bStringTable.data, bStringTable.length); + + // Read RuleFile. + byteArray bRuleFile; + bRuleFile.length = content.length - bStringTable.length; + bRuleFile.data = new BYTE[ bRuleFile.length ]; + dis2.read(bRuleFile); + + // 4J-JEV: I don't believe that the path-name is ever used. + //DLCGameRulesFile *dlcgr = new DLCGameRulesFile(L"__PLACEHOLDER__"); + //dlcgr->addData(bRuleFile.data,bRuleFile.length); + + if (readRuleFile(lgo, bRuleFile.data, bRuleFile.length, strings)) + { + // Set current gen options and ruleset. + //createdLevelGenerationOptions->setFromSaveGame(true); + lgo->setSrc(LevelGenerationOptions::eSrc_fromSave); + setLevelGenerationOptions( lgo ); + //m_currentGameRuleDefinitions = lgo->getRequiredGameRules(); + } + else + { + delete lgo; + } + + //delete [] content.data; + + // Close and return. + dis2.close(); + bais2.close(); + + return ; +} + +// 4J-JEV: Reverse of loadGameRules. +void GameRuleManager::saveGameRules(byte **dOut, UINT *dSize) +{ + if (m_currentGameRuleDefinitions == NULL && + m_currentLevelGenerationOptions == NULL) + { + app.DebugPrintf("GameRuleManager:: Nothing here to save."); + *dOut = NULL; + *dSize = 0; + return; + } + + app.DebugPrintf("GameRuleManager::saveGameRules:\n"); + + // Initialise output stream. + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + + // Write header. + + // VERSION NUMBER + dos.writeShort( 0x1 ); // version_number + + // Write 8 bytes of empty space in case we need them later. + // Mainly useful for the ones we save embedded in game saves. + for (UINT i = 0; i < 8; i++) + dos.writeByte(0x0); + + dos.writeByte(APPROPRIATE_COMPRESSION_TYPE); // m_compressionType + + // -- START COMPRESSED -- // + ByteArrayOutputStream compr_baos; + DataOutputStream compr_dos(&compr_baos); + + if (m_currentGameRuleDefinitions == NULL) + { + compr_dos.writeInt( 0 ); // numStrings for StringTable + compr_dos.writeInt( version_number ); + compr_dos.writeByte(Compression::eCompressionType_None); // compression type + for (int i=0; i<2; i++) compr_dos.writeByte(0x0); // Padding. + compr_dos.writeInt( 0 ); // StringLookup.length + compr_dos.writeInt( 0 ); // SchematicFiles.length + compr_dos.writeInt( 0 ); // XmlObjects.length + } + else + { + StringTable *st = m_currentGameRuleDefinitions->getStringTable(); + + if (st == NULL) + { + app.DebugPrintf("GameRuleManager::saveGameRules: StringTable == NULL!"); + } + else + { + // Write string table. + byteArray stba; + m_currentGameRuleDefinitions->getStringTable()->getData(&stba.data, &stba.length); + compr_dos.writeInt( stba.length ); + compr_dos.write( stba ); + + // Write game rule file to second + // buffer and generate string lookup. + writeRuleFile(&compr_dos); + } + } + + // Compress compr_dos and write to dos. + byteArray compr_ba(new BYTE[ compr_baos.buf.length ], compr_baos.buf.length); + Compression::getCompression()->CompressLZXRLE( compr_ba.data, &compr_ba.length, + compr_baos.buf.data, compr_baos.buf.length ); + + app.DebugPrintf("\tcompr_ba.length=%d.\n\tcompr_baos.buf.length=%d.\n", + compr_ba.length, compr_baos.buf.length ); + + dos.writeInt( compr_ba.length ); // Write length + dos.writeInt( compr_baos.buf.length ); + dos.write(compr_ba); + + delete [] compr_ba.data; + + compr_dos.close(); + compr_baos.close(); + // -- END COMPRESSED -- // + + // return + *dSize = baos.buf.length; + *dOut = baos.buf.data; + + baos.buf.data = NULL; + + dos.close(); baos.close(); +} + +// 4J-JEV: Reverse of readRuleFile. +void GameRuleManager::writeRuleFile(DataOutputStream *dos) +{ + // Write Header + dos->writeShort(version_number); // Version number. + dos->writeByte(Compression::eCompressionType_None); // compression type + for (int i=0; i<8; i++) dos->writeBoolean(false); // Padding. + + // Write string lookup. + int numStrings = ConsoleGameRules::eGameRuleType_Count + ConsoleGameRules::eGameRuleAttr_Count; + dos->writeInt(numStrings); + for (int i = 0; i < ConsoleGameRules::eGameRuleType_Count; i++) dos->writeUTF( wchTagNameA[i] ); + for (int i = 0; i < ConsoleGameRules::eGameRuleAttr_Count; i++) dos->writeUTF( wchAttrNameA[i] ); + + // Write schematic files. + unordered_map<wstring, ConsoleSchematicFile *> *files; + files = getLevelGenerationOptions()->getUnfinishedSchematicFiles(); + dos->writeInt( files->size() ); + for (AUTO_VAR(it, files->begin()); it != files->end(); it++) + { + wstring filename = it->first; + ConsoleSchematicFile *file = it->second; + + ByteArrayOutputStream fileBaos; + DataOutputStream fileDos(&fileBaos); + file->save(&fileDos); + + dos->writeUTF(filename); + //dos->writeInt(file->m_data.length); + dos->writeInt(fileBaos.buf.length); + dos->write((byteArray)fileBaos.buf); + + fileDos.close(); fileBaos.close(); + } + + // Write xml objects. + dos->writeInt( 2 ); // numChildren + m_currentLevelGenerationOptions->write(dos); + m_currentGameRuleDefinitions->write(dos); +} + +bool GameRuleManager::readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT dSize, StringTable *strings) //(DLCGameRulesFile *dlcFile, StringTable *strings) +{ + bool levelGenAdded = false; + bool gameRulesAdded = false; + LevelGenerationOptions *levelGenerator = lgo;//new LevelGenerationOptions(); + LevelRuleset *gameRules = new LevelRuleset(); + + //DWORD dwLen = 0; + //PBYTE pbData = dlcFile->getData(dwLen); + //byteArray data(pbData,dwLen); + + byteArray data(dIn, dSize); + ByteArrayInputStream bais(data); + DataInputStream dis(&bais); + + // Read File. + + // version_number + __int64 version = dis.readShort(); + unsigned char compressionType = 0; + if(version == 0) + { + for (int i = 0; i < 14; i++) dis.readByte(); // Read padding. + } + else + { + compressionType = dis.readByte(); + + // Read the spare bytes we inserted for future use + for(int i = 0; i < 8; ++i) dis.readBoolean(); + } + + ByteArrayInputStream *contentBais = NULL; + DataInputStream *contentDis = NULL; + + if(compressionType == Compression::eCompressionType_None) + { + // No compression + // No need to read buffer size, as we can read the stream as it is; + app.DebugPrintf("De-compressing game rules with: None\n"); + contentDis = &dis; + } + else + { + unsigned int uncompressedSize = dis.readInt(); + unsigned int compressedSize = dis.readInt(); + byteArray compressedBuffer(compressedSize); + dis.read(compressedBuffer); + + byteArray decompressedBuffer = byteArray(uncompressedSize); + + switch(compressionType) + { + case Compression::eCompressionType_None: + memcpy(decompressedBuffer.data, compressedBuffer.data, uncompressedSize); + break; + + case Compression::eCompressionType_RLE: + app.DebugPrintf("De-compressing game rules with: RLE\n"); + Compression::getCompression()->Decompress( decompressedBuffer.data, &decompressedBuffer.length, compressedBuffer.data, compressedSize); + break; + + default: + app.DebugPrintf("De-compressing game rules."); +#ifndef _CONTENT_PACKAGE + assert( compressionType == APPROPRIATE_COMPRESSION_TYPE ); +#endif + // 4J-JEV: DecompressLZXRLE uses the correct platform specific compression type. (need to assert that the data is compressed with it though). + Compression::getCompression()->DecompressLZXRLE(decompressedBuffer.data, &decompressedBuffer.length, compressedBuffer.data, compressedSize); + break; +/* 4J-JEV: + Each platform has only 1 method of compression, 'compression.h' file deals with it. + + case Compression::eCompressionType_LZXRLE: + app.DebugPrintf("De-compressing game rules with: LZX+RLE\n"); + Compression::getCompression()->DecompressLZXRLE( decompressedBuffer.data, &uncompressedSize, compressedBuffer.data, compressedSize); + break; + default: + app.DebugPrintf("Invalid compression type %d found\n", compressionType); + __debugbreak(); + + delete [] compressedBuffer.data; delete [] decompressedBuffer.data; + dis.close(); bais.reset(); + + if(!gameRulesAdded) delete gameRules; + return false; + */ + }; + + delete [] compressedBuffer.data; + + contentBais = new ByteArrayInputStream(decompressedBuffer); + contentDis = new DataInputStream(contentBais); + } + + // string lookup. + UINT numStrings = contentDis->readInt(); + vector<wstring> tagsAndAtts; + for (UINT i = 0; i < numStrings; i++) + tagsAndAtts.push_back( contentDis->readUTF() ); + + unordered_map<int, ConsoleGameRules::EGameRuleType> tagIdMap; + for(int type = (int)ConsoleGameRules::eGameRuleType_Root; type < (int)ConsoleGameRules::eGameRuleType_Count; ++type) + { + for(UINT i = 0; i < numStrings; ++i) + { + if(tagsAndAtts[i].compare(wchTagNameA[type]) == 0) + { + tagIdMap.insert( unordered_map<int, ConsoleGameRules::EGameRuleType>::value_type(i, (ConsoleGameRules::EGameRuleType)type) ); + break; + } + } + } + + // 4J-JEV: TODO: As yet unused. + /* + unordered_map<int, ConsoleGameRules::EGameRuleAttr> attrIdMap; + for(int attr = (int)ConsoleGameRules::eGameRuleAttr_descriptionName; attr < (int)ConsoleGameRules::eGameRuleAttr_Count; ++attr) + { + for (UINT i = 0; i < numStrings; i++) + { + if (tagsAndAtts[i].compare(wchAttrNameA[attr]) == 0) + { + tagIdMap.insert( unordered_map<int, ConsoleGameRules::EGameRuleAttr>::value_type(i , (ConsoleGameRules::EGameRuleAttr)attr) ); + break; + } + } + }*/ + + // subfile + UINT numFiles = contentDis->readInt(); + for (UINT i = 0; i < numFiles; i++) + { + wstring sFilename = contentDis->readUTF(); + int length = contentDis->readInt(); + byteArray ba( length ); + + contentDis->read(ba); + + levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length); + + } + + LEVEL_GEN_ID lgoID = LEVEL_GEN_ID_NULL; + + // xml objects + UINT numObjects = contentDis->readInt(); + for(UINT i = 0; i < numObjects; ++i) + { + int tagId = contentDis->readInt(); + ConsoleGameRules::EGameRuleType tagVal = ConsoleGameRules::eGameRuleType_Invalid; + AUTO_VAR(it,tagIdMap.find(tagId)); + if(it != tagIdMap.end()) tagVal = it->second; + + GameRuleDefinition *rule = NULL; + + if(tagVal == ConsoleGameRules::eGameRuleType_LevelGenerationOptions) + { + rule = levelGenerator; + levelGenAdded = true; + //m_levelGenerators.addLevelGenerator(L"",levelGenerator); + lgoID = addLevelGenerationOptions(levelGenerator); + levelGenerator->loadStringTable(strings); + } + else if(tagVal == ConsoleGameRules::eGameRuleType_LevelRules) + { + rule = gameRules; + gameRulesAdded = true; + m_levelRules.addLevelRule(L"",gameRules); + levelGenerator->setRequiredGameRules(gameRules); + gameRules->loadStringTable(strings); + } + + readAttributes(contentDis, &tagsAndAtts, rule); + readChildren(contentDis, &tagsAndAtts, &tagIdMap, rule); + } + + if(compressionType != 0) + { + // Not default + contentDis->close(); + if(contentBais != NULL) delete contentBais; + delete contentDis; + } + + dis.close(); + bais.reset(); + + //if(!levelGenAdded) { delete levelGenerator; levelGenerator = NULL; } + if(!gameRulesAdded) delete gameRules; + + return true; + //return levelGenerator; +} + +LevelGenerationOptions *GameRuleManager::readHeader(DLCGameRulesHeader *grh) +{ + LevelGenerationOptions *out = + new LevelGenerationOptions(); + + + out->setSrc(LevelGenerationOptions::eSrc_fromDLC); + out->setGrSource(grh); + addLevelGenerationOptions(out); + + return out; +} + +void GameRuleManager::readAttributes(DataInputStream *dis, vector<wstring> *tagsAndAtts, GameRuleDefinition *rule) +{ + int numAttrs = dis->readInt(); + for (UINT att = 0; att < numAttrs; ++att) + { + int attID = dis->readInt(); + wstring value = dis->readUTF(); + + if(rule != NULL) rule->addAttribute(tagsAndAtts->at(attID),value); + } +} + +void GameRuleManager::readChildren(DataInputStream *dis, vector<wstring> *tagsAndAtts, unordered_map<int, ConsoleGameRules::EGameRuleType> *tagIdMap, GameRuleDefinition *rule) +{ + int numChildren = dis->readInt(); + for(UINT child = 0; child < numChildren; ++child) + { + int tagId = dis->readInt(); + ConsoleGameRules::EGameRuleType tagVal = ConsoleGameRules::eGameRuleType_Invalid; + AUTO_VAR(it,tagIdMap->find(tagId)); + if(it != tagIdMap->end()) tagVal = it->second; + + GameRuleDefinition *childRule = NULL; + if(rule != NULL) childRule = rule->addChild(tagVal); + + readAttributes(dis,tagsAndAtts,childRule); + readChildren(dis,tagsAndAtts,tagIdMap,childRule); + } +} + +void GameRuleManager::processSchematics(LevelChunk *levelChunk) +{ + if(getLevelGenerationOptions() != NULL) + { + LevelGenerationOptions *levelGenOptions = getLevelGenerationOptions(); + levelGenOptions->processSchematics(levelChunk); + } +} + +void GameRuleManager::processSchematicsLighting(LevelChunk *levelChunk) +{ + if(getLevelGenerationOptions() != NULL) + { + LevelGenerationOptions *levelGenOptions = getLevelGenerationOptions(); + levelGenOptions->processSchematicsLighting(levelChunk); + } +} + +void GameRuleManager::loadDefaultGameRules() +{ +#ifdef _XBOX +#ifdef _TU_BUILD + wstring fileRoot = L"UPDATE:\\res\\GameRules\\Tutorial.pck"; +#else + wstring fileRoot = L"GAME:\\res\\TitleUpdate\\GameRules\\Tutorial.pck"; +#endif + File packedTutorialFile(fileRoot); + if(loadGameRulesPack(&packedTutorialFile)) + { + m_levelGenerators.getLevelGenerators()->at(0)->setWorldName(app.GetString(IDS_PLAY_TUTORIAL)); + //m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(L"Tutorial"); + m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(app.GetString(IDS_TUTORIALSAVENAME)); + } + +#ifndef _CONTENT_PACKAGE + // 4J Stu - Remove these just now + //File testRulesPath(L"GAME:\\GameRules"); + //vector<File *> *packFiles = testRulesPath.listFiles(); + + //for(AUTO_VAR(it,packFiles->begin()); it != packFiles->end(); ++it) + //{ + // loadGameRulesPack(*it); + //} + //delete packFiles; +#endif + +#else // _XBOX + + wstring fpTutorial = L"Tutorial.pck"; + if(app.getArchiveFileSize(fpTutorial) >= 0) + { + DLCPack *pack = new DLCPack(L"",0xffffffff); + DWORD dwFilesProcessed = 0; + if ( app.m_dlcManager.readDLCDataFile(dwFilesProcessed,fpTutorial,pack,true) ) + { + app.m_dlcManager.addPack(pack); + m_levelGenerators.getLevelGenerators()->at(0)->setWorldName(app.GetString(IDS_PLAY_TUTORIAL)); + m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(app.GetString(IDS_TUTORIALSAVENAME)); + } + else delete pack; + } + /*StringTable *strings = new StringTable(baStrings.data, baStrings.length); + LevelGenerationOptions *lgo = new LevelGenerationOptions(); + lgo->setGrSource( new JustGrSource() ); + lgo->setSrc( LevelGenerationOptions::eSrc_tutorial ); + readRuleFile(lgo, tutorial.data, tutorial.length, strings); + lgo->setLoadedData();*/ + +#endif +} + +bool GameRuleManager::loadGameRulesPack(File *path) +{ + bool success = false; +#ifdef _XBOX + if(path->exists()) + { + DLCPack *pack = new DLCPack(L"",0xffffffff); + DWORD dwFilesProcessed = 0; + if( app.m_dlcManager.readDLCDataFile(dwFilesProcessed, path->getPath(),pack)) + { + app.m_dlcManager.addPack(pack); + success = true; + } + else + { + delete pack; + } + } +#endif + return success; +} + +void GameRuleManager::setLevelGenerationOptions(LevelGenerationOptions *levelGen) +{ + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = levelGen; + + if(m_currentLevelGenerationOptions != NULL && m_currentLevelGenerationOptions->requiresGameRules() ) + { + m_currentGameRuleDefinitions = m_currentLevelGenerationOptions->getRequiredGameRules(); + } + + if(m_currentLevelGenerationOptions != NULL) + m_currentLevelGenerationOptions->reset_start(); +} + +LPCWSTR GameRuleManager::GetGameRulesString(const wstring &key) +{ + if(m_currentGameRuleDefinitions != NULL && !key.empty() ) + { + return m_currentGameRuleDefinitions->getString(key); + } + else + { + return L""; + } +} + +LEVEL_GEN_ID GameRuleManager::addLevelGenerationOptions(LevelGenerationOptions *lgo) +{ + vector<LevelGenerationOptions *> *lgs = m_levelGenerators.getLevelGenerators(); + + for (int i = 0; i<lgs->size(); i++) + if (lgs->at(i) == lgo) + return i; + + lgs->push_back(lgo); + return lgs->size() - 1; +} + +void GameRuleManager::unloadCurrentGameRules() +{ + if (m_currentLevelGenerationOptions != NULL) + { + if (m_currentGameRuleDefinitions != NULL + && m_currentLevelGenerationOptions->isFromSave()) + m_levelRules.removeLevelRule( m_currentGameRuleDefinitions ); + + if (m_currentLevelGenerationOptions->isFromSave()) + { + m_levelGenerators.removeLevelGenerator( m_currentLevelGenerationOptions ); + + delete m_currentLevelGenerationOptions; + } + else if (m_currentLevelGenerationOptions->isFromDLC()) + { + m_currentLevelGenerationOptions->reset_finish(); + } + } + + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = NULL; +} diff --git a/Minecraft.Client/Common/GameRules/GameRuleManager.h b/Minecraft.Client/Common/GameRules/GameRuleManager.h new file mode 100644 index 00000000..e9e983b8 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleManager.h @@ -0,0 +1,80 @@ +#pragma once +using namespace std; + +#include "LevelGenerators.h" +#include "LevelRules.h" +class LevelGenerationOptions; +class RootGameRulesDefinition; +class LevelChunk; +class DLCPack; +class DLCGameRulesFile; +class DLCGameRulesHeader; +class StringTable; +class GameRuleDefinition; +class DataInputStream; +class DataOutputStream; +class WstringLookup; + +#define GAME_RULE_SAVENAME L"requiredGameRules.grf" + +// 4J-JEV: +#define LEVEL_GEN_ID int +#define LEVEL_GEN_ID_NULL 0 + +class GameRuleManager +{ +public: + static WCHAR *wchTagNameA[ConsoleGameRules::eGameRuleType_Count]; + static WCHAR *wchAttrNameA[ConsoleGameRules::eGameRuleAttr_Count]; + + static const short version_number = 2; + +private: + LevelGenerationOptions *m_currentLevelGenerationOptions; + LevelRuleset *m_currentGameRuleDefinitions; + LevelGenerators m_levelGenerators; + LevelRules m_levelRules; + +public: + GameRuleManager(); + + void loadGameRules(DLCPack *); + + LevelGenerationOptions *loadGameRules(byte *dIn, UINT dSize); + void loadGameRules(LevelGenerationOptions *lgo, byte *dIn, UINT dSize); + + void saveGameRules(byte **dOut, UINT *dSize); + +private: + LevelGenerationOptions *readHeader(DLCGameRulesHeader *grh); + + void writeRuleFile(DataOutputStream *dos); + +public: + bool readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT dSize, StringTable *strings); //(DLCGameRulesFile *dlcFile, StringTable *strings); + +private: + void readAttributes(DataInputStream *dis, vector<wstring> *tagsAndAtts, GameRuleDefinition *rule); + void readChildren(DataInputStream *dis, vector<wstring> *tagsAndAtts, unordered_map<int, ConsoleGameRules::EGameRuleType> *tagIdMap, GameRuleDefinition *rule); + +public: + void processSchematics(LevelChunk *levelChunk); + void processSchematicsLighting(LevelChunk *levelChunk); + void loadDefaultGameRules(); + +private: + bool loadGameRulesPack(File *path); + + LEVEL_GEN_ID addLevelGenerationOptions(LevelGenerationOptions *); + +public: + vector<LevelGenerationOptions *> *getLevelGenerators() { return m_levelGenerators.getLevelGenerators(); } + void setLevelGenerationOptions(LevelGenerationOptions *levelGen); + LevelRuleset *getGameRuleDefinitions() { return m_currentGameRuleDefinitions; } + LevelGenerationOptions *getLevelGenerationOptions() { return m_currentLevelGenerationOptions; } + LPCWSTR GetGameRulesString(const wstring &key); + + // 4J-JEV: + // Properly cleans-up and unloads the current set of gameRules. + void unloadCurrentGameRules(); +}; diff --git a/Minecraft.Client/Common/GameRules/GameRulesInstance.h b/Minecraft.Client/Common/GameRules/GameRulesInstance.h new file mode 100644 index 00000000..064e086d --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRulesInstance.h @@ -0,0 +1,24 @@ +#pragma once +using namespace std; +#include <vector> +#include "GameRule.h" + +class GameRuleDefinition; + +// The game rule manager belongs to a player/server or other object, and maintains their current state for each of +// the rules that apply to them +class GameRulesInstance : public GameRule +{ +public: + // These types are used by the GameRuleDefinition to know which rules to add to this GameRulesInstance + enum EGameRulesInstanceType + { + eGameRulesInstanceType_ServerPlayer, + eGameRulesInstanceType_Server, + eGameRulesInstanceType_Count + }; + +public: + GameRulesInstance(GameRuleDefinition *definition, Connection *connection) : GameRule(definition,connection) {} + // Functions for all the hooks should go here +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp new file mode 100644 index 00000000..717b066e --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp @@ -0,0 +1,514 @@ +#include "stdafx.h" + +#include <unordered_set> + +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Pos.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\StringTable.h" +#include "LevelGenerationOptions.h" +#include "ConsoleGameRules.h" + +JustGrSource::JustGrSource() +{ + m_displayName = L"Default_DisplayName"; + m_worldName= L"Default_WorldName"; + m_defaultSaveName = L"Default_DefaultSaveName"; + m_bRequiresTexturePack = false; + m_requiredTexturePackId = 0; + m_grfPath = L"__NO_GRF_PATH__"; + m_bRequiresBaseSave = false; +} + +bool JustGrSource::requiresTexturePack() {return m_bRequiresTexturePack;} +UINT JustGrSource::getRequiredTexturePackId() {return m_requiredTexturePackId;} +wstring JustGrSource::getDefaultSaveName() {return m_defaultSaveName;} +LPCWSTR JustGrSource::getWorldName() {return m_worldName.c_str();} +LPCWSTR JustGrSource::getDisplayName() {return m_displayName.c_str();} +wstring JustGrSource::getGrfPath() {return m_grfPath;} +bool JustGrSource::requiresBaseSave() { return m_bRequiresBaseSave; }; +wstring JustGrSource::getBaseSavePath() { return m_baseSavePath; }; + +void JustGrSource::setRequiresTexturePack(bool x) {m_bRequiresTexturePack = x;} +void JustGrSource::setRequiredTexturePackId(UINT x) {m_requiredTexturePackId = x;} +void JustGrSource::setDefaultSaveName(const wstring &x) {m_defaultSaveName = x;} +void JustGrSource::setWorldName(const wstring &x) {m_worldName = x;} +void JustGrSource::setDisplayName(const wstring &x) {m_displayName = x;} +void JustGrSource::setGrfPath(const wstring &x) {m_grfPath = x;} +void JustGrSource::setBaseSavePath(const wstring &x) { m_baseSavePath = x; m_bRequiresBaseSave = true; } + +bool JustGrSource::ready() { return true; } + +LevelGenerationOptions::LevelGenerationOptions() +{ + m_spawnPos = NULL; + m_stringTable = NULL; + + m_hasLoadedData = false; + + m_seed = 0; + m_useFlatWorld = false; + m_bHaveMinY = false; + m_minY = INT_MAX; + m_bRequiresGameRules = false; + + m_pbBaseSaveData = NULL; + m_dwBaseSaveSize = 0; +} + +LevelGenerationOptions::~LevelGenerationOptions() +{ + clearSchematics(); + if(m_spawnPos != NULL) delete m_spawnPos; + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end(); ++it) + { + delete *it; + } + for(AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); ++it) + { + delete *it; + } + + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + { + delete *it; + } + + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + { + delete *it; + } + + if (m_stringTable) + if (!isTutorial()) + delete m_stringTable; + + if (isFromSave()) delete m_pSrc; +} + +ConsoleGameRules::EGameRuleType LevelGenerationOptions::getActionType() { return ConsoleGameRules::eGameRuleType_LevelGenerationOptions; } + +void LevelGenerationOptions::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnX); + dos->writeUTF(_toString(m_spawnPos->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnY); + dos->writeUTF(_toString(m_spawnPos->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnZ); + dos->writeUTF(_toString(m_spawnPos->z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_seed); + dos->writeUTF(_toString(m_seed)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_flatworld); + dos->writeUTF(_toString(m_useFlatWorld)); +} + +void LevelGenerationOptions::getChildren(vector<GameRuleDefinition *> *children) +{ + GameRuleDefinition::getChildren(children); + + vector<ApplySchematicRuleDefinition *> used_schematics; + for (AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end(); it++) + if ( !(*it)->isComplete() ) + used_schematics.push_back( *it ); + + for(AUTO_VAR(it, m_structureRules.begin()); it!=m_structureRules.end(); it++) + children->push_back( *it ); + for(AUTO_VAR(it, used_schematics.begin()); it!=used_schematics.end(); it++) + children->push_back( *it ); + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + children->push_back( *it ); + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + children->push_back( *it ); +} + +GameRuleDefinition *LevelGenerationOptions::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_ApplySchematic) + { + rule = new ApplySchematicRuleDefinition(this); + m_schematicRules.push_back((ApplySchematicRuleDefinition *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_GenerateStructure) + { + rule = new ConsoleGenerateStructure(); + m_structureRules.push_back((ConsoleGenerateStructure *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_BiomeOverride) + { + rule = new BiomeOverride(); + m_biomeOverrides.push_back((BiomeOverride *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_StartFeature) + { + rule = new StartFeature(); + m_features.push_back((StartFeature *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"LevelGenerationOptions: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void LevelGenerationOptions::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"seed") == 0) + { + m_seed = _fromString<__int64>(attributeValue); + app.DebugPrintf("LevelGenerationOptions: Adding parameter m_seed=%I64d\n",m_seed); + } + else if(attributeName.compare(L"spawnX") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->x = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnX=%d\n",value); + } + else if(attributeName.compare(L"spawnY") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->y = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnY=%d\n",value); + } + else if(attributeName.compare(L"spawnZ") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->z = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnZ=%d\n",value); + } + else if(attributeName.compare(L"flatworld") == 0) + { + if(attributeValue.compare(L"true") == 0) m_useFlatWorld = true; + app.DebugPrintf("LevelGenerationOptions: Adding parameter flatworld=%s\n",m_useFlatWorld?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"saveName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setDefaultSaveName( string ); + else setDefaultSaveName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter saveName=%ls\n", getDefaultSaveName().c_str()); + } + else if(attributeName.compare(L"worldName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setWorldName( string ); + else setWorldName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter worldName=%ls\n", getWorldName()); + } + else if(attributeName.compare(L"displayName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setDisplayName( string ); + else setDisplayName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter displayName=%ls\n", getDisplayName()); + } + else if(attributeName.compare(L"texturePackId") == 0) + { + setRequiredTexturePackId( _fromString<unsigned int>(attributeValue) ); + setRequiresTexturePack( true ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter texturePackId=%0x\n", getRequiredTexturePackId()); + } + else if(attributeName.compare(L"isTutorial") == 0) + { + if(attributeValue.compare(L"true") == 0) setSrc(eSrc_tutorial); + app.DebugPrintf("LevelGenerationOptions: Adding parameter isTutorial=%s\n",isTutorial()?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"baseSaveName") == 0) + { + setBaseSavePath( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter baseSaveName=%ls\n", getBaseSavePath().c_str()); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void LevelGenerationOptions::processSchematics(LevelChunk *chunk) +{ + PIXBeginNamedEvent(0,"Processing schematics for chunk (%d,%d)", chunk->x, chunk->z); + AABB *chunkBox = AABB::newTemp(chunk->x*16,0,chunk->z*16,chunk->x*16 + 16,Level::maxBuildHeight,chunk->z*16 + 16); + for( AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + rule->processSchematic(chunkBox, chunk); + } + + int cx = (chunk->x << 4); + int cz = (chunk->z << 4); + + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + + if (structureStart->getBoundingBox()->intersects(cx, cz, cx + 15, cz + 15)) + { + BoundingBox *bb = new BoundingBox(cx, cz, cx + 15, cz + 15); + structureStart->postProcess(chunk->level, NULL, bb); + delete bb; + } + } + PIXEndNamedEvent(); +} + +void LevelGenerationOptions::processSchematicsLighting(LevelChunk *chunk) +{ + PIXBeginNamedEvent(0,"Processing schematics (lighting) for chunk (%d,%d)", chunk->x, chunk->z); + AABB *chunkBox = AABB::newTemp(chunk->x*16,0,chunk->z*16,chunk->x*16 + 16,Level::maxBuildHeight,chunk->z*16 + 16); + for( AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + rule->processSchematicLighting(chunkBox, chunk); + } + PIXEndNamedEvent(); +} + +bool LevelGenerationOptions::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + PIXBeginNamedEvent(0,"Check Intersects"); + + // As an optimisation, we can quickly discard things below a certain y which makes most ore checks faster due to + // a) ores generally being below ground/sea level and b) tutorial world additions generally being above ground/sea level + if(!m_bHaveMinY) + { + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + int minY = rule->getMinY(); + if(minY < m_minY) m_minY = minY; + } + + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + int minY = structureStart->getMinY(); + if(minY < m_minY) m_minY = minY; + } + + m_bHaveMinY = true; + } + + // 4J Stu - We DO NOT intersect if our upper bound is below the lower bound for all schematics + if( y1 < m_minY ) return false; + + bool intersects = false; + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + intersects = rule->checkIntersects(x0,y0,z0,x1,y1,z1); + if(intersects) break; + } + + if(!intersects) + { + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + intersects = structureStart->checkIntersects(x0,y0,z0,x1,y1,z1); + if(intersects) break; + } + } + PIXEndNamedEvent(); + return intersects; +} + +void LevelGenerationOptions::clearSchematics() +{ + for(AUTO_VAR(it, m_schematics.begin()); it != m_schematics.end(); ++it) + { + delete it->second; + } + m_schematics.clear(); +} + +ConsoleSchematicFile *LevelGenerationOptions::loadSchematicFile(const wstring &filename, PBYTE pbData, DWORD dwLen) +{ + // If we have already loaded this, just return + AUTO_VAR(it, m_schematics.find(filename)); + if(it != m_schematics.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"We have already loaded schematic file %ls\n", filename.c_str() ); +#endif + it->second->incrementRefCount(); + return it->second; + } + + ConsoleSchematicFile *schematic = NULL; + byteArray data(pbData,dwLen); + ByteArrayInputStream bais(data); + DataInputStream dis(&bais); + schematic = new ConsoleSchematicFile(); + schematic->load(&dis); + m_schematics[filename] = schematic; + bais.reset(); + return schematic; +} + +ConsoleSchematicFile *LevelGenerationOptions::getSchematicFile(const wstring &filename) +{ + ConsoleSchematicFile *schematic = NULL; + // If we have already loaded this, just return + AUTO_VAR(it, m_schematics.find(filename)); + if(it != m_schematics.end()) + { + schematic = it->second; + } + return schematic; +} + +void LevelGenerationOptions::releaseSchematicFile(const wstring &filename) +{ + // 4J Stu - We don't want to delete them when done, but probably want to keep a set of active schematics for the current world + //AUTO_VAR(it, m_schematics.find(filename)); + //if(it != m_schematics.end()) + //{ + // ConsoleSchematicFile *schematic = it->second; + // schematic->decrementRefCount(); + // if(schematic->shouldDelete()) + // { + // delete schematic; + // m_schematics.erase(it); + // } + //} +} + +void LevelGenerationOptions::loadStringTable(StringTable *table) +{ + m_stringTable = table; +} + +LPCWSTR LevelGenerationOptions::getString(const wstring &key) +{ + if(m_stringTable == NULL) + { + return L""; + } + else + { + return m_stringTable->getString(key); + } +} + +void LevelGenerationOptions::getBiomeOverride(int biomeId, BYTE &tile, BYTE &topTile) +{ + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + { + BiomeOverride *bo = *it; + if(bo->isBiome(biomeId)) + { + bo->getTileValues(tile,topTile); + break; + } + } +} + +bool LevelGenerationOptions::isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature) +{ + bool isFeature = false; + + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + { + StartFeature *sf = *it; + if(sf->isFeatureChunk(chunkX, chunkZ, feature)) + { + isFeature = true; + break; + } + } + return isFeature; +} + +unordered_map<wstring, ConsoleSchematicFile *> *LevelGenerationOptions::getUnfinishedSchematicFiles() +{ + // Clean schematic rules. + unordered_set<wstring> usedFiles = unordered_set<wstring>(); + for (AUTO_VAR(it, m_schematicRules.begin()); it!=m_schematicRules.end(); it++) + if ( !(*it)->isComplete() ) + usedFiles.insert( (*it)->getSchematicName() ); + + // Clean schematic files. + unordered_map<wstring, ConsoleSchematicFile *> *out + = new unordered_map<wstring, ConsoleSchematicFile *>(); + for (AUTO_VAR(it, usedFiles.begin()); it!=usedFiles.end(); it++) + out->insert( pair<wstring, ConsoleSchematicFile *>(*it, getSchematicFile(*it)) ); + + return out; +} + +void LevelGenerationOptions::reset_start() +{ + for ( AUTO_VAR( it, m_schematicRules.begin()); + it != m_schematicRules.end(); + it++ ) + { + (*it)->reset(); + } +} + +void LevelGenerationOptions::reset_finish() +{ + //if (m_spawnPos) { delete m_spawnPos; m_spawnPos = NULL; } + //if (m_stringTable) { delete m_stringTable; m_stringTable = NULL; } + + if (isFromDLC()) + { + m_hasLoadedData = false; + } +} + + +GrSource *LevelGenerationOptions::info() { return m_pSrc; } +void LevelGenerationOptions::setSrc(eSrc src) { m_src = src; } +LevelGenerationOptions::eSrc LevelGenerationOptions::getSrc() { return m_src; } + +bool LevelGenerationOptions::isTutorial() { return getSrc() == eSrc_tutorial; } +bool LevelGenerationOptions::isFromSave() { return getSrc() == eSrc_fromSave; } +bool LevelGenerationOptions::isFromDLC() { return getSrc() == eSrc_fromDLC; } + +bool LevelGenerationOptions::requiresTexturePack() { return info()->requiresTexturePack(); } +UINT LevelGenerationOptions::getRequiredTexturePackId() { return info()->getRequiredTexturePackId(); } +wstring LevelGenerationOptions::getDefaultSaveName() { return info()->getDefaultSaveName(); } +LPCWSTR LevelGenerationOptions::getWorldName() { return info()->getWorldName(); } +LPCWSTR LevelGenerationOptions::getDisplayName() { return info()->getDisplayName(); } +wstring LevelGenerationOptions::getGrfPath() { return info()->getGrfPath(); } +bool LevelGenerationOptions::requiresBaseSave() { return info()->requiresBaseSave(); } +wstring LevelGenerationOptions::getBaseSavePath() { return info()->getBaseSavePath(); } + +void LevelGenerationOptions::setGrSource(GrSource *grs) { m_pSrc = grs; } + +void LevelGenerationOptions::setRequiresTexturePack(bool x) { info()->setRequiresTexturePack(x); } +void LevelGenerationOptions::setRequiredTexturePackId(UINT x) { info()->setRequiredTexturePackId(x); } +void LevelGenerationOptions::setDefaultSaveName(const wstring &x) { info()->setDefaultSaveName(x); } +void LevelGenerationOptions::setWorldName(const wstring &x) { info()->setWorldName(x); } +void LevelGenerationOptions::setDisplayName(const wstring &x) { info()->setDisplayName(x); } +void LevelGenerationOptions::setGrfPath(const wstring &x) { info()->setGrfPath(x); } +void LevelGenerationOptions::setBaseSavePath(const wstring &x) { info()->setBaseSavePath(x); } + +bool LevelGenerationOptions::ready() { return info()->ready(); } + +void LevelGenerationOptions::setBaseSaveData(PBYTE pbData, DWORD dwSize) { m_pbBaseSaveData = pbData; m_dwBaseSaveSize = dwSize; } +PBYTE LevelGenerationOptions::getBaseSaveData(DWORD &size) { size = m_dwBaseSaveSize; return m_pbBaseSaveData; } +bool LevelGenerationOptions::hasBaseSaveData() { return m_dwBaseSaveSize > 0 && m_pbBaseSaveData != NULL; } +void LevelGenerationOptions::deleteBaseSaveData() { if(m_pbBaseSaveData) delete m_pbBaseSaveData; m_pbBaseSaveData = NULL; m_dwBaseSaveSize = 0; } + +bool LevelGenerationOptions::hasLoadedData() { return m_hasLoadedData; } +void LevelGenerationOptions::setLoadedData() { m_hasLoadedData = true; } + +__int64 LevelGenerationOptions::getLevelSeed() { return m_seed; } +Pos *LevelGenerationOptions::getSpawnPos() { return m_spawnPos; } +bool LevelGenerationOptions::getuseFlatWorld() { return m_useFlatWorld; } + +bool LevelGenerationOptions::requiresGameRules() { return m_bRequiresGameRules; } +void LevelGenerationOptions::setRequiredGameRules(LevelRuleset *rules) { m_requiredGameRules = rules; m_bRequiresGameRules = true; } +LevelRuleset *LevelGenerationOptions::getRequiredGameRules() { return m_requiredGameRules; }
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h new file mode 100644 index 00000000..0cc9da79 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h @@ -0,0 +1,216 @@ +#pragma once +using namespace std; + +#pragma message("LevelGenerationOptions.h ") + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructureFeature.h" + +class ApplySchematicRuleDefinition; +class LevelChunk; +class ConsoleGenerateStructure; +class ConsoleSchematicFile; +class LevelRuleset; +class BiomeOverride; +class StartFeature; + +class GrSource +{ +public: + // 4J-JEV: + // Moved all this here; I didn't like that all this header information + // was being mixed in with all the game information as they have + // completely different lifespans. + + virtual bool requiresTexturePack()=0; + virtual UINT getRequiredTexturePackId()=0; + virtual wstring getDefaultSaveName()=0; + virtual LPCWSTR getWorldName()=0; + virtual LPCWSTR getDisplayName()=0; + virtual wstring getGrfPath()=0; + virtual bool requiresBaseSave() = 0; + virtual wstring getBaseSavePath() = 0; + + virtual void setRequiresTexturePack(bool)=0; + virtual void setRequiredTexturePackId(UINT)=0; + virtual void setDefaultSaveName(const wstring &)=0; + virtual void setWorldName(const wstring &)=0; + virtual void setDisplayName(const wstring &)=0; + virtual void setGrfPath(const wstring &)=0; + virtual void setBaseSavePath(const wstring &)=0; + + virtual bool ready()=0; + + //virtual void getGrfData(PBYTE &pData, DWORD &pSize)=0; +}; + +class JustGrSource : public GrSource +{ +protected: + wstring m_worldName; + wstring m_displayName; + wstring m_defaultSaveName; + bool m_bRequiresTexturePack; + int m_requiredTexturePackId; + wstring m_grfPath; + wstring m_baseSavePath; + bool m_bRequiresBaseSave; + +public: + virtual bool requiresTexturePack(); + virtual UINT getRequiredTexturePackId(); + virtual wstring getDefaultSaveName(); + virtual LPCWSTR getWorldName(); + virtual LPCWSTR getDisplayName(); + virtual wstring getGrfPath(); + virtual bool requiresBaseSave(); + virtual wstring getBaseSavePath(); + + virtual void setRequiresTexturePack(bool x); + virtual void setRequiredTexturePackId(UINT x); + virtual void setDefaultSaveName(const wstring &x); + virtual void setWorldName(const wstring &x); + virtual void setDisplayName(const wstring &x); + virtual void setGrfPath(const wstring &x); + virtual void setBaseSavePath(const wstring &x); + + virtual bool ready(); + + JustGrSource(); +}; + +class LevelGenerationOptions : public GameRuleDefinition +{ +public: + enum eSrc + { + eSrc_none, + + eSrc_fromSave, // Neither content or header is persistent. + + eSrc_fromDLC, // Header is persistent, content should be deleted to conserve space. + + eSrc_tutorial, // Both header and content is persistent, content cannot be reloaded. + + eSrc_MAX + }; + +private: + eSrc m_src; + + GrSource *m_pSrc; + GrSource *info(); + + bool m_hasLoadedData; + + PBYTE m_pbBaseSaveData; + DWORD m_dwBaseSaveSize; + +public: + + void setSrc(eSrc src); + eSrc getSrc(); + + bool isTutorial(); + bool isFromSave(); + bool isFromDLC(); + + bool requiresTexturePack(); + UINT getRequiredTexturePackId(); + wstring getDefaultSaveName(); + LPCWSTR getWorldName(); + LPCWSTR getDisplayName(); + wstring getGrfPath(); + bool requiresBaseSave(); + wstring getBaseSavePath(); + + void setGrSource(GrSource *grs); + + void setRequiresTexturePack(bool x); + void setRequiredTexturePackId(UINT x); + void setDefaultSaveName(const wstring &x); + void setWorldName(const wstring &x); + void setDisplayName(const wstring &x); + void setGrfPath(const wstring &x); + void setBaseSavePath(const wstring &x); + + bool ready(); + + void setBaseSaveData(PBYTE pbData, DWORD dwSize); + PBYTE getBaseSaveData(DWORD &size); + bool hasBaseSaveData(); + void deleteBaseSaveData(); + + bool hasLoadedData(); + void setLoadedData(); + +private: + // This should match the "MapOptionsRule" definition in the XML schema + __int64 m_seed; + bool m_useFlatWorld; + Pos *m_spawnPos; + vector<ApplySchematicRuleDefinition *> m_schematicRules; + vector<ConsoleGenerateStructure *> m_structureRules; + bool m_bHaveMinY; + int m_minY; + unordered_map<wstring, ConsoleSchematicFile *> m_schematics; + vector<BiomeOverride *> m_biomeOverrides; + vector<StartFeature *> m_features; + + bool m_bRequiresGameRules; + LevelRuleset *m_requiredGameRules; + + StringTable *m_stringTable; + +public: + LevelGenerationOptions(); + ~LevelGenerationOptions(); + + virtual ConsoleGameRules::EGameRuleType getActionType(); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + __int64 getLevelSeed(); + Pos *getSpawnPos(); + bool getuseFlatWorld(); + + void processSchematics(LevelChunk *chunk); + void processSchematicsLighting(LevelChunk *chunk); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + +private: + void clearSchematics(); + +public: + ConsoleSchematicFile *loadSchematicFile(const wstring &filename, PBYTE pbData, DWORD dwLen); + +public: + ConsoleSchematicFile *getSchematicFile(const wstring &filename); + void releaseSchematicFile(const wstring &filename); + + bool requiresGameRules(); + void setRequiredGameRules(LevelRuleset *rules); + LevelRuleset *getRequiredGameRules(); + + void getBiomeOverride(int biomeId, BYTE &tile, BYTE &topTile); + bool isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature); + + void loadStringTable(StringTable *table); + LPCWSTR getString(const wstring &key); + + unordered_map<wstring, ConsoleSchematicFile *> *getUnfinishedSchematicFiles(); + + // 4J-JEV: + // ApplySchematicRules contain limited state + // which needs to be reset BEFORE a new game starts. + void reset_start(); + + // 4J-JEV: + // This file contains state that needs to be deleted + // or reset once a game has finished. + void reset_finish(); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerators.cpp b/Minecraft.Client/Common/GameRules/LevelGenerators.cpp new file mode 100644 index 00000000..653a26d0 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerators.cpp @@ -0,0 +1,26 @@ +#include "stdafx.h" +#include "LevelGenerationOptions.h" +#include "LevelGenerators.h" + + +LevelGenerators::LevelGenerators() +{ +} + +void LevelGenerators::addLevelGenerator(const wstring &displayName, LevelGenerationOptions *generator) +{ + if(!displayName.empty()) generator->setDisplayName(displayName); + m_levelGenerators.push_back(generator); +} + +void LevelGenerators::removeLevelGenerator(LevelGenerationOptions *generator) +{ + vector<LevelGenerationOptions *>::iterator it; + while ( (it = find( m_levelGenerators.begin(), + m_levelGenerators.end(), + generator ) ) + != m_levelGenerators.end() ) + { + m_levelGenerators.erase(it); + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerators.h b/Minecraft.Client/Common/GameRules/LevelGenerators.h new file mode 100644 index 00000000..824b8387 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerators.h @@ -0,0 +1,19 @@ +#pragma once + +using namespace std; + +class LevelGenerationOptions; + +class LevelGenerators +{ +private: + vector<LevelGenerationOptions *> m_levelGenerators; + +public: + LevelGenerators(); + + void addLevelGenerator(const wstring &displayName, LevelGenerationOptions *generator); + void removeLevelGenerator(LevelGenerationOptions *generator); + + vector<LevelGenerationOptions *> *getLevelGenerators() { return &m_levelGenerators; } +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRules.cpp b/Minecraft.Client/Common/GameRules/LevelRules.cpp new file mode 100644 index 00000000..b7c8a8a5 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRules.cpp @@ -0,0 +1,20 @@ +#include "stdafx.h" +#include "LevelRules.h" + + +LevelRules::LevelRules() +{ +} + +void LevelRules::addLevelRule(const wstring &displayName, PBYTE pbData, DWORD dwLen) +{ +} + +void LevelRules::addLevelRule(const wstring &displayName, LevelRuleset *rootRule) +{ +} + +void LevelRules::removeLevelRule(LevelRuleset *removing) +{ + // TODO ? +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRules.h b/Minecraft.Client/Common/GameRules/LevelRules.h new file mode 100644 index 00000000..a94a2123 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRules.h @@ -0,0 +1,14 @@ +#pragma once + +class LevelRuleset; + +class LevelRules +{ +public: + LevelRules(); + + void addLevelRule(const wstring &displayName, PBYTE pbData, DWORD dwLen); + void addLevelRule(const wstring &displayName, LevelRuleset *rootRule); + + void removeLevelRule(LevelRuleset *removing); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRuleset.cpp b/Minecraft.Client/Common/GameRules/LevelRuleset.cpp new file mode 100644 index 00000000..1c7ecd47 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRuleset.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\StringTable.h" +#include "ConsoleGameRules.h" +#include "LevelRuleset.h" + +LevelRuleset::LevelRuleset() +{ + m_stringTable = NULL; +} + +LevelRuleset::~LevelRuleset() +{ + for(AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); ++it) + { + delete *it; + } +} + +void LevelRuleset::getChildren(vector<GameRuleDefinition *> *children) +{ + CompoundGameRuleDefinition::getChildren(children); + for (AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *LevelRuleset::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_NamedArea) + { + rule = new NamedAreaRuleDefinition(); + m_areas.push_back((NamedAreaRuleDefinition *)rule); + } + else + { + rule = CompoundGameRuleDefinition::addChild(ruleType); + } + return rule; +} + +void LevelRuleset::loadStringTable(StringTable *table) +{ + m_stringTable = table; +} + +LPCWSTR LevelRuleset::getString(const wstring &key) +{ + if(m_stringTable == NULL) + { + return L""; + } + else + { + return m_stringTable->getString(key); + } +} + +AABB *LevelRuleset::getNamedArea(const wstring &areaName) +{ + AABB *area = NULL; + for(AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); ++it) + { + if( (*it)->getName().compare(areaName) == 0 ) + { + area = (*it)->getArea(); + break; + } + } + return area; +} diff --git a/Minecraft.Client/Common/GameRules/LevelRuleset.h b/Minecraft.Client/Common/GameRules/LevelRuleset.h new file mode 100644 index 00000000..bbb17c43 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRuleset.h @@ -0,0 +1,27 @@ +#pragma once + +#include "CompoundGameRuleDefinition.h" + +class NamedAreaRuleDefinition; + +class LevelRuleset : public CompoundGameRuleDefinition +{ +private: + vector<NamedAreaRuleDefinition *> m_areas; + StringTable *m_stringTable; +public: + LevelRuleset(); + ~LevelRuleset(); + + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_LevelRules; } + + void loadStringTable(StringTable *table); + LPCWSTR getString(const wstring &key); + + AABB *getNamedArea(const wstring &areaName); + + StringTable *getStringTable() { return m_stringTable; } +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp new file mode 100644 index 00000000..41ff15e8 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp @@ -0,0 +1,84 @@ +#include "stdafx.h" +#include "NamedAreaRuleDefinition.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" + +NamedAreaRuleDefinition::NamedAreaRuleDefinition() +{ + m_name = L""; + m_area = AABB::newPermanent(0,0,0,0,0,0); +} + +NamedAreaRuleDefinition::~NamedAreaRuleDefinition() +{ + delete m_area; +} + +void NamedAreaRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 7); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_name); + dos->writeUTF(m_name); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x0); + dos->writeUTF(_toString(m_area->x0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y0); + dos->writeUTF(_toString(m_area->y0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z0); + dos->writeUTF(_toString(m_area->z0)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x1); + dos->writeUTF(_toString(m_area->x1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y1); + dos->writeUTF(_toString(m_area->y1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z1); + dos->writeUTF(_toString(m_area->z1)); +} + +void NamedAreaRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"name") == 0) + { + m_name = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"NamedAreaRuleDefinition: Adding parameter name=%ls\n",m_name.c_str()); +#endif + } + else if(attributeName.compare(L"x0") == 0) + { + m_area->x0 = _fromString<int>(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter x0=%f\n",m_area->x0); + } + else if(attributeName.compare(L"y0") == 0) + { + m_area->y0 = _fromString<int>(attributeValue); + if(m_area->y0 < 0) m_area->y0 = 0; + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter y0=%f\n",m_area->y0); + } + else if(attributeName.compare(L"z0") == 0) + { + m_area->z0 = _fromString<int>(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter z0=%f\n",m_area->z0); + } + else if(attributeName.compare(L"x1") == 0) + { + m_area->x1 = _fromString<int>(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter x1=%f\n",m_area->x1); + } + else if(attributeName.compare(L"y1") == 0) + { + m_area->y1 = _fromString<int>(attributeValue); + if(m_area->y1 < 0) m_area->y1 = 0; + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter y1=%f\n",m_area->y1); + } + else if(attributeName.compare(L"z1") == 0) + { + m_area->z1 = _fromString<int>(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter z1=%f\n",m_area->z1); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} diff --git a/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h new file mode 100644 index 00000000..7cf7db19 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class NamedAreaRuleDefinition : public GameRuleDefinition +{ +private: + wstring m_name; + AABB *m_area; + +public: + NamedAreaRuleDefinition(); + ~NamedAreaRuleDefinition(); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_NamedArea; } + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + AABB *getArea() { return m_area; } + wstring getName() { return m_name; } +}; diff --git a/Minecraft.Client/Common/GameRules/StartFeature.cpp b/Minecraft.Client/Common/GameRules/StartFeature.cpp new file mode 100644 index 00000000..9d5f15c0 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/StartFeature.cpp @@ -0,0 +1,53 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "StartFeature.h" + +StartFeature::StartFeature() +{ + m_chunkX = 0; + m_chunkZ = 0; + m_feature = StructureFeature::eFeature_Temples; +} + +void StartFeature::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_chunkX); + dos->writeUTF(_toString(m_chunkX)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_chunkZ); + dos->writeUTF(_toString(m_chunkZ)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_feature); + dos->writeUTF(_toString((int)m_feature)); +} + +void StartFeature::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"chunkX") == 0) + { + int value = _fromString<int>(attributeValue); + m_chunkX = value; + app.DebugPrintf("StartFeature: Adding parameter chunkX=%d\n",m_chunkX); + } + else if(attributeName.compare(L"chunkZ") == 0) + { + int value = _fromString<int>(attributeValue); + m_chunkZ = value; + app.DebugPrintf("StartFeature: Adding parameter chunkZ=%d\n",m_chunkZ); + } + else if(attributeName.compare(L"feature") == 0) + { + int value = _fromString<int>(attributeValue); + m_feature = (StructureFeature::EFeatureTypes)value; + app.DebugPrintf("StartFeature: Adding parameter feature=%d\n",m_feature); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool StartFeature::isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature) +{ + return chunkX == m_chunkX && chunkZ == m_chunkZ && feature == m_feature; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/StartFeature.h b/Minecraft.Client/Common/GameRules/StartFeature.h new file mode 100644 index 00000000..d3f1280a --- /dev/null +++ b/Minecraft.Client/Common/GameRules/StartFeature.h @@ -0,0 +1,22 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructureFeature.h" + +class StartFeature : public GameRuleDefinition +{ +private: + int m_chunkX, m_chunkZ; + StructureFeature::EFeatureTypes m_feature; + +public: + StartFeature(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_StartFeature; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp new file mode 100644 index 00000000..6e55cd45 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp @@ -0,0 +1,171 @@ +#include "stdafx.h" +#include "UpdatePlayerRuleDefinition.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\Pos.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.food.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" + +UpdatePlayerRuleDefinition::UpdatePlayerRuleDefinition() +{ + m_bUpdateHealth = m_bUpdateFood = m_bUpdateYRot = false;; + m_health = 0; + m_food = 0; + m_spawnPos = NULL; + m_yRot = 0.0f; +} + +UpdatePlayerRuleDefinition::~UpdatePlayerRuleDefinition() +{ + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + delete *it; + } +} + +void UpdatePlayerRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + int attrCount = 3; + if(m_bUpdateHealth) ++attrCount; + if(m_bUpdateFood) ++attrCount; + if(m_bUpdateYRot) ++attrCount; + GameRuleDefinition::writeAttributes(dos, numAttributes + attrCount ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnX); + dos->writeUTF(_toString(m_spawnPos->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnY); + dos->writeUTF(_toString(m_spawnPos->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnZ); + dos->writeUTF(_toString(m_spawnPos->z)); + + if(m_bUpdateYRot) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_yRot); + dos->writeUTF(_toString(m_yRot)); + } + if(m_bUpdateHealth) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_food); + dos->writeUTF(_toString(m_health)); + } + if(m_bUpdateFood) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_health); + dos->writeUTF(_toString(m_food)); + } +} + +void UpdatePlayerRuleDefinition::getChildren(vector<GameRuleDefinition *> *children) +{ + GameRuleDefinition::getChildren(children); + for(AUTO_VAR(it, m_items.begin()); it!=m_items.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *UpdatePlayerRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddItem) + { + rule = new AddItemRuleDefinition(); + m_items.push_back((AddItemRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"UpdatePlayerRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void UpdatePlayerRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"spawnX") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->x = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnX=%d\n",value); + } + else if(attributeName.compare(L"spawnY") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->y = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnY=%d\n",value); + } + else if(attributeName.compare(L"spawnZ") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString<int>(attributeValue); + m_spawnPos->z = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnZ=%d\n",value); + } + else if(attributeName.compare(L"health") == 0) + { + int value = _fromString<int>(attributeValue); + m_health = value; + m_bUpdateHealth = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter health=%d\n",value); + } + else if(attributeName.compare(L"food") == 0) + { + int value = _fromString<int>(attributeValue); + m_food = value; + m_bUpdateFood = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter health=%d\n",value); + } + else if(attributeName.compare(L"yRot") == 0) + { + float value = _fromString<float>(attributeValue); + m_yRot = value; + m_bUpdateYRot = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter yRot=%f\n",value); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void UpdatePlayerRuleDefinition::postProcessPlayer(shared_ptr<Player> player) +{ + if(m_bUpdateHealth) + { + player->lastHealth = m_health; + player->setHealth(m_health); + } + + if(m_bUpdateFood) + { + player->getFoodData()->setFoodLevel(m_food); + } + + double x = player->x; + double y = player->y; + double z = player->z; + float yRot = player->yRot; + float xRot = player->xRot; + if(m_spawnPos != NULL) + { + x = m_spawnPos->x; + y = m_spawnPos->y; + z = m_spawnPos->z; + } + + if(m_bUpdateYRot) + { + yRot = m_yRot; + } + + if(m_spawnPos != NULL || m_bUpdateYRot) player->absMoveTo(x,y,z,yRot,xRot); + + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + AddItemRuleDefinition *addItem = *it; + + addItem->addItemToContainer(player->inventory, -1); + } +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h new file mode 100644 index 00000000..538aefa1 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h @@ -0,0 +1,33 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" + +class AddItemRuleDefinition; +class Pos; + +class UpdatePlayerRuleDefinition : public GameRuleDefinition +{ +private: + vector<AddItemRuleDefinition *> m_items; + + bool m_bUpdateHealth, m_bUpdateFood, m_bUpdateYRot, m_bUpdateInventory; + int m_health; + int m_food; + Pos *m_spawnPos; + float m_yRot; + +public: + UpdatePlayerRuleDefinition(); + ~UpdatePlayerRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_UpdatePlayerRule; } + + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual void postProcessPlayer(shared_ptr<Player> player); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp new file mode 100644 index 00000000..965405ae --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp @@ -0,0 +1,82 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "UseTileRuleDefinition.h" + +UseTileRuleDefinition::UseTileRuleDefinition() +{ + m_tileId = -1; + m_useCoords = false; +} + +void UseTileRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_tileId); + dos->writeUTF(_toString(m_tileId)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_useCoords); + dos->writeUTF(_toString(m_useCoords)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_coordinates.x)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_coordinates.y)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_coordinates.z)); +} + +void UseTileRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"tileId") == 0) + { + m_tileId = _fromString<int>(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter tileId=%d\n",m_tileId); + } + else if(attributeName.compare(L"useCoords") == 0) + { + m_useCoords = _fromString<bool>(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter useCoords=%s\n",m_useCoords?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"x") == 0) + { + m_coordinates.x = _fromString<int>(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter x=%d\n",m_coordinates.x); + } + else if(attributeName.compare(L"y") == 0) + { + m_coordinates.y = _fromString<int>(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter y=%d\n",m_coordinates.y); + } + else if(attributeName.compare(L"z") == 0) + { + m_coordinates.z = _fromString<int>(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter z=%d\n",m_coordinates.z); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool UseTileRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = false; + if( m_tileId == tileId ) + { + if( !m_useCoords || (m_coordinates.x == x && m_coordinates.y == y && m_coordinates.z == z) ) + { + if(!getComplete(rule)) + { + statusChanged = true; + setComplete(rule,true); + app.DebugPrintf("Completed UseTileRule with info - t:%d, coords:%s, x:%d, y:%d, z:%d\n", m_tileId,m_useCoords?"TRUE":"FALSE",m_coordinates.x,m_coordinates.y,m_coordinates.z); + + // Send a packet or some other announcement here + } + } + } + return statusChanged; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h new file mode 100644 index 00000000..ad64bfe4 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h @@ -0,0 +1,24 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\Pos.h" + +class UseTileRuleDefinition : public GameRuleDefinition +{ +private: + // These values should map directly to the xsd definition for this Rule + int m_tileId; + bool m_useCoords; + Pos m_coordinates; + +public: + UseTileRuleDefinition(); + + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_UseTileRule; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp new file mode 100644 index 00000000..6d687b36 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp @@ -0,0 +1,104 @@ +#include "stdafx.h" +#include "XboxStructureActionGenerateBox.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" + +XboxStructureActionGenerateBox::XboxStructureActionGenerateBox() +{ + m_x0 = m_y0 = m_z0 = m_x1 = m_y1 = m_z1 = m_edgeTile = m_fillTile = 0; + m_skipAir = false; +} + +void XboxStructureActionGenerateBox::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + ConsoleGenerateStructureAction::writeAttributes(dos, numAttrs + 9); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x0); + dos->writeUTF(_toString(m_x0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y0); + dos->writeUTF(_toString(m_y0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z0); + dos->writeUTF(_toString(m_z0)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x1); + dos->writeUTF(_toString(m_x1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y1); + dos->writeUTF(_toString(m_y1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z1); + dos->writeUTF(_toString(m_z1)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_edgeTile); + dos->writeUTF(_toString(m_edgeTile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_fillTile); + dos->writeUTF(_toString(m_fillTile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_skipAir); + dos->writeUTF(_toString(m_skipAir)); +} + +void XboxStructureActionGenerateBox::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x0") == 0) + { + int value = _fromString<int>(attributeValue); + m_x0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter x0=%d\n",m_x0); + } + else if(attributeName.compare(L"y0") == 0) + { + int value = _fromString<int>(attributeValue); + m_y0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter y0=%d\n",m_y0); + } + else if(attributeName.compare(L"z0") == 0) + { + int value = _fromString<int>(attributeValue); + m_z0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter z0=%d\n",m_z0); + } + else if(attributeName.compare(L"x1") == 0) + { + int value = _fromString<int>(attributeValue); + m_x1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter x1=%d\n",m_x1); + } + else if(attributeName.compare(L"y1") == 0) + { + int value = _fromString<int>(attributeValue); + m_y1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter y1=%d\n",m_y1); + } + else if(attributeName.compare(L"z1") == 0) + { + int value = _fromString<int>(attributeValue); + m_z1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter z1=%d\n",m_z1); + } + else if(attributeName.compare(L"edgeTile") == 0) + { + int value = _fromString<int>(attributeValue); + m_edgeTile = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter edgeTile=%d\n",m_edgeTile); + } + else if(attributeName.compare(L"fillTile") == 0) + { + int value = _fromString<int>(attributeValue); + m_fillTile = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter fillTile=%d\n",m_fillTile); + } + else if(attributeName.compare(L"skipAir") == 0) + { + if(attributeValue.compare(L"true") == 0) m_skipAir = true; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter skipAir=%s\n",m_skipAir?"TRUE":"FALSE"); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionGenerateBox::generateBoxInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + app.DebugPrintf("XboxStructureActionGenerateBox - generating a box\n"); + structure->generateBox(level,chunkBB,m_x0,m_y0,m_z0,m_x1,m_y1,m_z1,m_edgeTile,m_fillTile,m_skipAir); + return true; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h new file mode 100644 index 00000000..78664d42 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h @@ -0,0 +1,26 @@ +#pragma once +#include "ConsoleGenerateStructureAction.h" + +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionGenerateBox : public ConsoleGenerateStructureAction +{ +private: + int m_x0, m_y0, m_z0, m_x1, m_y1, m_z1, m_edgeTile, m_fillTile; + bool m_skipAir; +public: + XboxStructureActionGenerateBox(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_GenerateBox; } + + virtual int getEndX() { return m_x1; } + virtual int getEndY() { return m_y1; } + virtual int getEndZ() { return m_z1; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool generateBoxInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp new file mode 100644 index 00000000..b816d5b6 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp @@ -0,0 +1,72 @@ +#include "stdafx.h" +#include "XboxStructureActionPlaceBlock.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" + +XboxStructureActionPlaceBlock::XboxStructureActionPlaceBlock() +{ + m_x = m_y = m_z = m_tile = m_data = 0; +} + +void XboxStructureActionPlaceBlock::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + ConsoleGenerateStructureAction::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_data); + dos->writeUTF(_toString(m_data)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_block); + dos->writeUTF(_toString(m_tile)); +} + + +void XboxStructureActionPlaceBlock::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x") == 0) + { + int value = _fromString<int>(attributeValue); + m_x = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter x=%d\n",m_x); + } + else if(attributeName.compare(L"y") == 0) + { + int value = _fromString<int>(attributeValue); + m_y = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter y=%d\n",m_y); + } + else if(attributeName.compare(L"z") == 0) + { + int value = _fromString<int>(attributeValue); + m_z = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter z=%d\n",m_z); + } + else if(attributeName.compare(L"block") == 0) + { + int value = _fromString<int>(attributeValue); + m_tile = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter block=%d\n",m_tile); + } + else if(attributeName.compare(L"data") == 0) + { + int value = _fromString<int>(attributeValue); + m_data = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter data=%d\n",m_data); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceBlock::placeBlockInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + app.DebugPrintf("XboxStructureActionPlaceBlock - placing a block\n"); + structure->placeBlock(level,m_tile,m_data,m_x,m_y,m_z,chunkBB); + return true; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h new file mode 100644 index 00000000..3ee377b9 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h @@ -0,0 +1,25 @@ +#pragma once +#include "ConsoleGenerateStructureAction.h" + +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionPlaceBlock : public ConsoleGenerateStructureAction +{ +protected: + int m_x, m_y, m_z, m_tile, m_data; +public: + XboxStructureActionPlaceBlock(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceBlock; } + + virtual int getEndX() { return m_x; } + virtual int getEndY() { return m_y; } + virtual int getEndZ() { return m_z; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeBlockInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp new file mode 100644 index 00000000..8184f45b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp @@ -0,0 +1,99 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XboxStructureActionPlaceContainer.h" +#include "AddItemRuleDefinition.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" + +XboxStructureActionPlaceContainer::XboxStructureActionPlaceContainer() +{ + m_tile = Tile::chest_Id; +} + +XboxStructureActionPlaceContainer::~XboxStructureActionPlaceContainer() +{ + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + delete *it; + } +} + +// 4J-JEV: Super class handles attr-facing fine. +//void XboxStructureActionPlaceContainer::writeAttributes(DataOutputStream *dos, UINT numAttrs) + + +void XboxStructureActionPlaceContainer::getChildren(vector<GameRuleDefinition *> *children) +{ + XboxStructureActionPlaceBlock::getChildren(children); + for(AUTO_VAR(it, m_items.begin()); it!=m_items.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *XboxStructureActionPlaceContainer::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddItem) + { + rule = new AddItemRuleDefinition(); + m_items.push_back((AddItemRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceContainer: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void XboxStructureActionPlaceContainer::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"facing") == 0) + { + int value = _fromString<int>(attributeValue); + m_data = value; + app.DebugPrintf("XboxStructureActionPlaceContainer: Adding parameter facing=%d\n",m_data); + } + else + { + XboxStructureActionPlaceBlock::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceContainer::placeContainerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + int worldX = structure->getWorldX( m_x, m_z ); + int worldY = structure->getWorldY( m_y ); + int worldZ = structure->getWorldZ( m_x, m_z ); + + if ( chunkBB->isInside( worldX, worldY, worldZ ) ) + { + if ( level->getTileEntity( worldX, worldY, worldZ ) != NULL ) + { + // Remove the current tile entity + level->removeTileEntity( worldX, worldY, worldZ ); + level->setTile( worldX, worldY, worldZ, 0 ); + } + + level->setTile( worldX, worldY, worldZ, m_tile ); + shared_ptr<Container> container = dynamic_pointer_cast<Container>(level->getTileEntity( worldX, worldY, worldZ )); + + app.DebugPrintf("XboxStructureActionPlaceContainer - placing a container at (%d,%d,%d)\n", worldX, worldY, worldZ); + if ( container != NULL ) + { + level->setData( worldX, worldY, worldZ, m_data); + // Add items + int slotId = 0; + for(AUTO_VAR(it, m_items.begin()); it != m_items.end() && (slotId < container->getContainerSize()); ++it, ++slotId ) + { + AddItemRuleDefinition *addItem = *it; + + addItem->addItemToContainer(container,slotId); + } + } + return true; + } + return false; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h new file mode 100644 index 00000000..6355ca11 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h @@ -0,0 +1,29 @@ +#pragma once + +#include "XboxStructureActionPlaceBlock.h" + +class AddItemRuleDefinition; +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionPlaceContainer : public XboxStructureActionPlaceBlock +{ +private: + vector<AddItemRuleDefinition *> m_items; +public: + XboxStructureActionPlaceContainer(); + ~XboxStructureActionPlaceContainer(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceContainer; } + + virtual void getChildren(vector<GameRuleDefinition *> *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + // 4J-JEV: Super class handles attr-facing fine. + //virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeContainerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +};
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp new file mode 100644 index 00000000..1eca3342 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XboxStructureActionPlaceSpawner.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" + +XboxStructureActionPlaceSpawner::XboxStructureActionPlaceSpawner() +{ + m_tile = Tile::mobSpawner_Id; + m_entityId = L"Pig"; +} + +XboxStructureActionPlaceSpawner::~XboxStructureActionPlaceSpawner() +{ +} + +void XboxStructureActionPlaceSpawner::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + XboxStructureActionPlaceBlock::writeAttributes(dos, numAttrs + 1); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_entity); + dos->writeUTF(m_entityId); +} + +void XboxStructureActionPlaceSpawner::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"entity") == 0) + { + m_entityId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceSpawner: Adding parameter entity=%ls\n",m_entityId.c_str()); +#endif + } + else + { + XboxStructureActionPlaceBlock::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceSpawner::placeSpawnerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + int worldX = structure->getWorldX( m_x, m_z ); + int worldY = structure->getWorldY( m_y ); + int worldZ = structure->getWorldZ( m_x, m_z ); + + if ( chunkBB->isInside( worldX, worldY, worldZ ) ) + { + if ( level->getTileEntity( worldX, worldY, worldZ ) != NULL ) + { + // Remove the current tile entity + level->removeTileEntity( worldX, worldY, worldZ ); + level->setTile( worldX, worldY, worldZ, 0 ); + } + + level->setTile( worldX, worldY, worldZ, m_tile ); + shared_ptr<MobSpawnerTileEntity> entity = dynamic_pointer_cast<MobSpawnerTileEntity>(level->getTileEntity( worldX, worldY, worldZ )); + +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceSpawner - placing a %ls spawner at (%d,%d,%d)\n", m_entityId.c_str(), worldX, worldY, worldZ); +#endif + if( entity != NULL ) + { + entity->setEntityId(m_entityId); + } + return true; + } + return false; +}
\ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h new file mode 100644 index 00000000..16000980 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h @@ -0,0 +1,24 @@ +#pragma once + +#include "XboxStructureActionPlaceBlock.h" + +class StructurePiece; +class Level; +class BoundingBox; +class GRFObject; + +class XboxStructureActionPlaceSpawner : public XboxStructureActionPlaceBlock +{ +private: + wstring m_entityId; +public: + XboxStructureActionPlaceSpawner(); + ~XboxStructureActionPlaceSpawner(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceSpawner; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeSpawnerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +};
\ No newline at end of file |
