aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Common/GameRules
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Common/GameRules
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.Client/Common/GameRules')
-rw-r--r--Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp70
-rw-r--r--Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h23
-rw-r--r--Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp127
-rw-r--r--Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h30
-rw-r--r--Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp249
-rw-r--r--Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h51
-rw-r--r--Minecraft.Client/Common/GameRules/BiomeOverride.cpp59
-rw-r--r--Minecraft.Client/Common/GameRules/BiomeOverride.h23
-rw-r--r--Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp117
-rw-r--r--Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h40
-rw-r--r--Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp66
-rw-r--r--Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h26
-rw-r--r--Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp118
-rw-r--r--Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h23
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleGameRules.h32
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h119
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp181
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h38
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h11
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp1020
-rw-r--r--Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h90
-rw-r--r--Minecraft.Client/Common/GameRules/GameRule.cpp97
-rw-r--r--Minecraft.Client/Common/GameRules/GameRule.h62
-rw-r--r--Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp151
-rw-r--r--Minecraft.Client/Common/GameRules/GameRuleDefinition.h66
-rw-r--r--Minecraft.Client/Common/GameRules/GameRuleManager.cpp767
-rw-r--r--Minecraft.Client/Common/GameRules/GameRuleManager.h80
-rw-r--r--Minecraft.Client/Common/GameRules/GameRulesInstance.h24
-rw-r--r--Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp514
-rw-r--r--Minecraft.Client/Common/GameRules/LevelGenerationOptions.h216
-rw-r--r--Minecraft.Client/Common/GameRules/LevelGenerators.cpp26
-rw-r--r--Minecraft.Client/Common/GameRules/LevelGenerators.h19
-rw-r--r--Minecraft.Client/Common/GameRules/LevelRules.cpp20
-rw-r--r--Minecraft.Client/Common/GameRules/LevelRules.h14
-rw-r--r--Minecraft.Client/Common/GameRules/LevelRuleset.cpp71
-rw-r--r--Minecraft.Client/Common/GameRules/LevelRuleset.h27
-rw-r--r--Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp84
-rw-r--r--Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h23
-rw-r--r--Minecraft.Client/Common/GameRules/StartFeature.cpp53
-rw-r--r--Minecraft.Client/Common/GameRules/StartFeature.h22
-rw-r--r--Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp171
-rw-r--r--Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h33
-rw-r--r--Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp82
-rw-r--r--Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h24
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp104
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h26
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp72
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h25
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp99
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h29
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp69
-rw-r--r--Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h24
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 &parameterName)
+{
+ 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 &parameterName,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 &parameterName);
+ void setParameter(const wstring &parameterName,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