summaryrefslogtreecommitdiffstats
path: root/src/WorldStorage
diff options
context:
space:
mode:
Diffstat (limited to 'src/WorldStorage')
-rw-r--r--src/WorldStorage/FastNBT.cpp2
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp120
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp96
4 files changed, 160 insertions, 60 deletions
diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp
index c6294b99c..ed8e8bb14 100644
--- a/src/WorldStorage/FastNBT.cpp
+++ b/src/WorldStorage/FastNBT.cpp
@@ -310,7 +310,7 @@ int cParsedNBT::FindTagByPath(int a_Tag, const AString & a_Path) const
{
continue;
}
- Tag = FindChildByName(Tag, a_Path.c_str() + Begin, i - Begin - 1);
+ Tag = FindChildByName(Tag, a_Path.c_str() + Begin, i - Begin);
if (Tag < 0)
{
return -1;
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 68e541eba..2420c905b 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -81,6 +81,18 @@ void cNBTChunkSerializer::Finish(void)
memset(m_BlockLight, 0, sizeof(m_BlockLight));
memset(m_BlockSkyLight, 0, sizeof(m_BlockSkyLight));
}
+
+ // Check if "Entity" and "TileEntities" lists exists. MCEdit requires this.
+ if (!m_HasHadEntity)
+ {
+ m_Writer.BeginList("Entities", TAG_Compound);
+ m_Writer.EndList();
+ }
+ if (!m_HasHadBlockEntity)
+ {
+ m_Writer.BeginList("TileEntities", TAG_Compound);
+ m_Writer.EndList();
+ }
}
@@ -458,35 +470,35 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
const char * EntityClass = NULL;
switch (a_Monster->GetMobType())
{
- case cMonster::mtBat: EntityClass = "Bat"; break;
- case cMonster::mtBlaze: EntityClass = "Blaze"; break;
- case cMonster::mtCaveSpider: EntityClass = "CaveSpider"; break;
- case cMonster::mtChicken: EntityClass = "Chicken"; break;
- case cMonster::mtCow: EntityClass = "Cow"; break;
- case cMonster::mtCreeper: EntityClass = "Creeper"; break;
- case cMonster::mtEnderDragon: EntityClass = "EnderDragon"; break;
- case cMonster::mtEnderman: EntityClass = "Enderman"; break;
- case cMonster::mtGhast: EntityClass = "Ghast"; break;
- case cMonster::mtGiant: EntityClass = "Giant"; break;
- case cMonster::mtHorse: EntityClass = "Horse"; break;
- case cMonster::mtIronGolem: EntityClass = "VillagerGolem"; break;
- case cMonster::mtMagmaCube: EntityClass = "LavaSlime"; break;
- case cMonster::mtMooshroom: EntityClass = "MushroomCow"; break;
- case cMonster::mtOcelot: EntityClass = "Ozelot"; break;
- case cMonster::mtPig: EntityClass = "Pig"; break;
- case cMonster::mtSheep: EntityClass = "Sheep"; break;
- case cMonster::mtSilverfish: EntityClass = "Silverfish"; break;
- case cMonster::mtSkeleton: EntityClass = "Skeleton"; break;
- case cMonster::mtSlime: EntityClass = "Slime"; break;
- case cMonster::mtSnowGolem: EntityClass = "SnowMan"; break;
- case cMonster::mtSpider: EntityClass = "Spider"; break;
- case cMonster::mtSquid: EntityClass = "Squid"; break;
- case cMonster::mtVillager: EntityClass = "Villager"; break;
- case cMonster::mtWitch: EntityClass = "Witch"; break;
- case cMonster::mtWither: EntityClass = "WitherBoss"; break;
- case cMonster::mtWolf: EntityClass = "Wolf"; break;
- case cMonster::mtZombie: EntityClass = "Zombie"; break;
- case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break;
+ case mtBat: EntityClass = "Bat"; break;
+ case mtBlaze: EntityClass = "Blaze"; break;
+ case mtCaveSpider: EntityClass = "CaveSpider"; break;
+ case mtChicken: EntityClass = "Chicken"; break;
+ case mtCow: EntityClass = "Cow"; break;
+ case mtCreeper: EntityClass = "Creeper"; break;
+ case mtEnderDragon: EntityClass = "EnderDragon"; break;
+ case mtEnderman: EntityClass = "Enderman"; break;
+ case mtGhast: EntityClass = "Ghast"; break;
+ case mtGiant: EntityClass = "Giant"; break;
+ case mtHorse: EntityClass = "Horse"; break;
+ case mtIronGolem: EntityClass = "VillagerGolem"; break;
+ case mtMagmaCube: EntityClass = "LavaSlime"; break;
+ case mtMooshroom: EntityClass = "MushroomCow"; break;
+ case mtOcelot: EntityClass = "Ozelot"; break;
+ case mtPig: EntityClass = "Pig"; break;
+ case mtSheep: EntityClass = "Sheep"; break;
+ case mtSilverfish: EntityClass = "Silverfish"; break;
+ case mtSkeleton: EntityClass = "Skeleton"; break;
+ case mtSlime: EntityClass = "Slime"; break;
+ case mtSnowGolem: EntityClass = "SnowMan"; break;
+ case mtSpider: EntityClass = "Spider"; break;
+ case mtSquid: EntityClass = "Squid"; break;
+ case mtVillager: EntityClass = "Villager"; break;
+ case mtWitch: EntityClass = "Witch"; break;
+ case mtWither: EntityClass = "WitherBoss"; break;
+ case mtWolf: EntityClass = "Wolf"; break;
+ case mtZombie: EntityClass = "Zombie"; break;
+ case mtZombiePigman: EntityClass = "PigZombie"; break;
default:
{
ASSERT(!"Unhandled monster type");
@@ -504,26 +516,28 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddFloat("", a_Monster->GetDropChanceBoots());
m_Writer.EndList();
m_Writer.AddByte("CanPickUpLoot", (char)a_Monster->CanPickUpLoot());
+ m_Writer.AddString("CustomName", a_Monster->GetCustomName());
+ m_Writer.AddByte("CustomNameVisible", (char)a_Monster->IsCustomNameAlwaysVisible());
switch (a_Monster->GetMobType())
{
- case cMonster::mtBat:
+ case mtBat:
{
m_Writer.AddByte("BatFlags", ((const cBat *)a_Monster)->IsHanging());
break;
}
- case cMonster::mtCreeper:
+ case mtCreeper:
{
m_Writer.AddByte("powered", ((const cCreeper *)a_Monster)->IsCharged());
m_Writer.AddByte("ignited", ((const cCreeper *)a_Monster)->IsBlowing());
break;
}
- case cMonster::mtEnderman:
+ case mtEnderman:
{
m_Writer.AddShort("carried", (Int16)((const cEnderman *)a_Monster)->GetCarriedBlock());
m_Writer.AddShort("carriedData", (Int16)((const cEnderman *)a_Monster)->GetCarriedMeta());
break;
}
- case cMonster::mtHorse:
+ case mtHorse:
{
const cHorse & Horse = *((const cHorse *)a_Monster);
m_Writer.AddByte("ChestedHorse", Horse.IsChested());
@@ -536,38 +550,38 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddByte("Saddle", Horse.IsSaddled());
break;
}
- case cMonster::mtMagmaCube:
+ case mtMagmaCube:
{
m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize());
break;
}
- case cMonster::mtSheep:
+ case mtSheep:
{
m_Writer.AddByte("Sheared", ((const cSheep *)a_Monster)->IsSheared());
m_Writer.AddByte("Color", ((const cSheep *)a_Monster)->GetFurColor());
break;
}
- case cMonster::mtSlime:
+ case mtSlime:
{
m_Writer.AddInt("Size", ((const cSlime *)a_Monster)->GetSize());
break;
}
- case cMonster::mtSkeleton:
+ case mtSkeleton:
{
m_Writer.AddByte("SkeletonType", (((const cSkeleton *)a_Monster)->IsWither() ? 1 : 0));
break;
}
- case cMonster::mtVillager:
+ case mtVillager:
{
m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
break;
}
- case cMonster::mtWither:
+ case mtWither:
{
m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks());
break;
}
- case cMonster::mtWolf:
+ case mtWolf:
{
const cWolf & Wolf = *((cWolf *)a_Monster);
if (!Wolf.GetOwnerName().empty())
@@ -580,10 +594,10 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
}
m_Writer.AddByte("Sitting", Wolf.IsSitting() ? 1 : 0);
m_Writer.AddByte("Angry", Wolf.IsAngry() ? 1 : 0);
- m_Writer.AddInt("CollarColor", Wolf.GetCollarColor());
+ m_Writer.AddByte("CollarColor", (unsigned char)Wolf.GetCollarColor());
break;
}
- case cMonster::mtZombie:
+ case mtZombie:
{
m_Writer.AddByte("IsVillager", (((const cZombie *)a_Monster)->IsVillagerZombie() ? 1 : 0));
m_Writer.AddByte("IsBaby", (((const cZombie *)a_Monster)->IsBaby() ? 1 : 0));
@@ -623,9 +637,9 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
{
cArrowEntity * Arrow = (cArrowEntity *)a_Projectile;
- m_Writer.AddInt("xTile", (Int16)Arrow->GetBlockHit().x);
- m_Writer.AddInt("yTile", (Int16)Arrow->GetBlockHit().y);
- m_Writer.AddInt("zTile", (Int16)Arrow->GetBlockHit().z);
+ m_Writer.AddShort("xTile", (Int16)Arrow->GetBlockHit().x);
+ m_Writer.AddShort("yTile", (Int16)Arrow->GetBlockHit().y);
+ m_Writer.AddShort("zTile", (Int16)Arrow->GetBlockHit().z);
m_Writer.AddByte("pickup", Arrow->GetPickupState());
m_Writer.AddDouble("damage", Arrow->GetDamageCoeff());
break;
@@ -763,6 +777,22 @@ void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid)
+void cNBTChunkSerializer::HeightMap(const cChunkDef::HeightMap * a_HeightMap)
+{
+ for (int RelX = 0; RelX < cChunkDef::Width; RelX++)
+ {
+ for (int RelZ = 0; RelZ < cChunkDef::Width; RelZ++)
+ {
+ int Height = cChunkDef::GetHeight(*a_HeightMap, RelX, RelZ);
+ m_VanillaHeightMap[(RelZ << 4) | RelX] = Height;
+ }
+ }
+}
+
+
+
+
+
void cNBTChunkSerializer::BiomeData(const cChunkDef::BiomeMap * a_BiomeMap)
{
memcpy(m_Biomes, a_BiomeMap, sizeof(m_Biomes));
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 4c229a65c..5ffab8cc5 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -59,6 +59,7 @@ class cNBTChunkSerializer :
public:
cChunkDef::BiomeMap m_Biomes;
unsigned char m_VanillaBiomes[cChunkDef::Width * cChunkDef::Width];
+ int m_VanillaHeightMap[cChunkDef::Width * cChunkDef::Width];
bool m_BiomesAreValid;
@@ -125,6 +126,7 @@ protected:
// cChunkDataSeparateCollector overrides:
virtual void LightIsValid(bool a_IsLightValid) override;
+ virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) override;
virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override;
virtual void Entity(cEntity * a_Entity) override;
virtual void BlockEntity(cBlockEntity * a_Entity) override;
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index fe309ce4e..092b9514c 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -51,6 +51,7 @@
#include "../Entities/ItemFrame.h"
#include "../Protocol/MojangAPI.h"
+#include "Server.h"
@@ -96,10 +97,26 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
if (!cFile::Exists(fnam))
{
cFastNBTWriter Writer;
- Writer.BeginCompound("");
- Writer.AddInt("SpawnX", (int)(a_World->GetSpawnX()));
- Writer.AddInt("SpawnY", (int)(a_World->GetSpawnY()));
- Writer.AddInt("SpawnZ", (int)(a_World->GetSpawnZ()));
+ Writer.BeginCompound("Data");
+ Writer.AddByte("allowCommands", 1);
+ Writer.AddByte("Difficulty", 2);
+ Writer.AddByte("hardcore", cRoot::Get()->GetServer()->IsHardcore() ? 1 : 0);
+ Writer.AddByte("initialized", 1);
+ Writer.AddByte("MapFeatures", 1);
+ Writer.AddByte("raining", a_World->IsWeatherRain() ? 1 : 0);
+ Writer.AddByte("thundering", a_World->IsWeatherStorm() ? 1 : 0);
+ Writer.AddInt("GameType", (int)a_World->GetGameMode());
+ Writer.AddInt("generatorVersion", 1);
+ Writer.AddInt("SpawnX", (int)a_World->GetSpawnX());
+ Writer.AddInt("SpawnY", (int)a_World->GetSpawnY());
+ Writer.AddInt("SpawnZ", (int)a_World->GetSpawnZ());
+ Writer.AddInt("version", 19133);
+ Writer.AddLong("DayTime", (Int64)a_World->GetTimeOfDay());
+ Writer.AddLong("Time", a_World->GetWorldAge());
+ Writer.AddLong("SizeOnDisk", 0);
+ Writer.AddString("generatorName", "default");
+ Writer.AddString("generatorOptions", "");
+ Writer.AddString("LevelName", a_World->GetName());
Writer.EndCompound();
Writer.Finish();
@@ -440,6 +457,7 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
a_Writer.BeginCompound("Level");
a_Writer.AddInt("xPos", a_Chunk.m_ChunkX);
a_Writer.AddInt("zPos", a_Chunk.m_ChunkZ);
+
cNBTChunkSerializer Serializer(a_Writer);
if (!m_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer))
{
@@ -454,7 +472,10 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
a_Writer.AddByteArray("Biomes", (const char *)(Serializer.m_VanillaBiomes), ARRAYCOUNT(Serializer.m_VanillaBiomes));
a_Writer.AddIntArray ("MCSBiomes", (const int *)(Serializer.m_Biomes), ARRAYCOUNT(Serializer.m_Biomes));
}
-
+
+ // Save heightmap (Vanilla require this):
+ a_Writer.AddIntArray("HeightMap", (const int *)Serializer.m_VanillaHeightMap, ARRAYCOUNT(Serializer.m_VanillaHeightMap));
+
// Save blockdata:
a_Writer.BeginList("Sections", TAG_Compound);
size_t SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
@@ -485,6 +506,9 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
{
a_Writer.AddByte("MCSIsLightValid", 1);
}
+
+ // Save the world age to the chunk data. Required by vanilla and mcedit.
+ a_Writer.AddLong("LastUpdate", m_World->GetWorldAge());
// Store the flag that the chunk has all the ores, trees, dungeons etc. MCS chunks are always complete.
a_Writer.AddByte("TerrainPopulated", 1);
@@ -1640,7 +1664,7 @@ void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT
if (Direction > 0)
{
Direction = (int)a_NBT.GetByte(Direction);
- if ((Direction < 0) || (Direction > 5))
+ if ((Direction < 2) || (Direction > 5))
{
a_Hanging.SetDirection(BLOCK_FACE_NORTH);
}
@@ -1728,7 +1752,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
// Load pickup state:
int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup");
- if (PickupIdx > 0)
+ if ((PickupIdx > 0) && (a_NBT.GetType(PickupIdx) == TAG_Byte))
{
Arrow->SetPickupState((cArrowEntity::ePickupState)a_NBT.GetByte(PickupIdx));
}
@@ -1736,7 +1760,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
{
// Try the older "player" tag:
int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player");
- if (PlayerIdx > 0)
+ if ((PlayerIdx > 0) && (a_NBT.GetType(PlayerIdx) == TAG_Byte))
{
Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative);
}
@@ -1744,7 +1768,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
// Load damage:
int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage");
- if (DamageIdx > 0)
+ if ((DamageIdx > 0) && (a_NBT.GetType(DamageIdx) == TAG_Double))
{
Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
}
@@ -1755,7 +1779,24 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
int InBlockZIdx = a_NBT.FindChildByName(a_TagIdx, "zTile");
if ((InBlockXIdx > 0) && (InBlockYIdx > 0) && (InBlockZIdx > 0))
{
- Arrow->SetBlockHit(Vector3i(a_NBT.GetInt(InBlockXIdx), a_NBT.GetInt(InBlockYIdx), a_NBT.GetInt(InBlockZIdx)));
+ if (a_NBT.GetType(InBlockXIdx) == a_NBT.GetType(InBlockYIdx) == a_NBT.GetType(InBlockZIdx))
+ {
+ switch (a_NBT.GetType(InBlockXIdx))
+ {
+ case TAG_Int:
+ {
+ // Old MCS code used this, keep reading it for compatibility reasons:
+ Arrow->SetBlockHit(Vector3i(a_NBT.GetInt(InBlockXIdx), a_NBT.GetInt(InBlockYIdx), a_NBT.GetInt(InBlockZIdx)));
+ break;
+ }
+ case TAG_Short:
+ {
+ // Vanilla uses this
+ Arrow->SetBlockHit(Vector3i((int)a_NBT.GetShort(InBlockXIdx), (int)a_NBT.GetShort(InBlockYIdx), (int)a_NBT.GetShort(InBlockZIdx)));
+ break;
+ }
+ }
+ }
}
// Store the new arrow in the entities list:
@@ -2464,13 +2505,13 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
LoadWolfOwner(*Monster.get(), a_NBT, a_TagIdx);
int SittingIdx = a_NBT.FindChildByName(a_TagIdx, "Sitting");
- if (SittingIdx > 0)
+ if ((SittingIdx > 0) && (a_NBT.GetType(SittingIdx) == TAG_Byte))
{
bool Sitting = ((a_NBT.GetByte(SittingIdx) == 1) ? true : false);
Monster->SetIsSitting(Sitting);
}
int AngryIdx = a_NBT.FindChildByName(a_TagIdx, "Angry");
- if (AngryIdx > 0)
+ if ((AngryIdx > 0) && (a_NBT.GetType(AngryIdx) == TAG_Byte))
{
bool Angry = ((a_NBT.GetByte(AngryIdx) == 1) ? true : false);
Monster->SetIsAngry(Angry);
@@ -2478,8 +2519,22 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
int CollarColorIdx = a_NBT.FindChildByName(a_TagIdx, "CollarColor");
if (CollarColorIdx > 0)
{
- int CollarColor = a_NBT.GetInt(CollarColorIdx);
- Monster->SetCollarColor(CollarColor);
+ switch (a_NBT.GetType(CollarColorIdx))
+ {
+ case TAG_Byte:
+ {
+ // Vanilla uses this
+ unsigned char CollarColor = a_NBT.GetByte(CollarColorIdx);
+ Monster->SetCollarColor(CollarColor);
+ break;
+ }
+ case TAG_Int:
+ {
+ // Old MCS code used this, keep reading it for compatibility reasons:
+ Monster->SetCollarColor(a_NBT.GetInt(CollarColorIdx));
+ break;
+ }
+ }
}
a_Entities.push_back(Monster.release());
}
@@ -2652,6 +2707,19 @@ bool cWSSAnvil::LoadMonsterBaseFromNBT(cMonster & a_Monster, const cParsedNBT &
a_Monster.SetCanPickUpLoot(CanPickUpLoot);
}
+ int CustomNameTag = a_NBT.FindChildByName(a_TagIdx, "CustomName");
+ if ((CustomNameTag > 0) && (a_NBT.GetType(CustomNameTag) == TAG_String))
+ {
+ a_Monster.SetCustomName(a_NBT.GetString(CustomNameTag));
+ }
+
+ int CustomNameVisibleTag = a_NBT.FindChildByName(a_TagIdx, "CustomNameVisible");
+ if ((CustomNameVisibleTag > 0) && (a_NBT.GetType(CustomNameVisibleTag) == TAG_Byte))
+ {
+ bool CustomNameVisible = (a_NBT.GetByte(CustomNameVisibleTag) == 1);
+ a_Monster.SetCustomNameAlwaysVisible(CustomNameVisible);
+ }
+
return true;
}