Merge pull request #669 from xdot/master
Implementation of in-game maps :D
This commit is contained in:
commit
f77720c43f
@ -1489,6 +1489,68 @@ a_Player:OpenWindow(Window);
|
|||||||
Inherits = "cWindow",
|
Inherits = "cWindow",
|
||||||
}, -- cLuaWindow
|
}, -- cLuaWindow
|
||||||
|
|
||||||
|
cMap =
|
||||||
|
{
|
||||||
|
Desc = [[
|
||||||
|
This class encapsulates a single in-game colored map.</p>
|
||||||
|
<p>
|
||||||
|
The contents (i.e. pixel data) of a cMap are dynamically updated by each
|
||||||
|
tracked {{cPlayer}} instance. Furthermore, a cMap maintains and periodically
|
||||||
|
updates a list of map decorators, which are objects drawn on the map that
|
||||||
|
can freely move (e.g. Player and item frame pointers).
|
||||||
|
]],
|
||||||
|
Functions =
|
||||||
|
{
|
||||||
|
EraseData = { Params = "", Return = "", Notes = "Erases all pixel data." },
|
||||||
|
GetCenterX = { Params = "", Return = "number", Notes = "Returns the X coord of the map's center." },
|
||||||
|
GetCenterZ = { Params = "", Return = "number", Notes = "Returns the Y coord of the map's center." },
|
||||||
|
GetDimension = { Params = "", Return = "eDimension", Notes = "Returns the dimension of the associated world." },
|
||||||
|
GetHeight = { Params = "", Return = "number", Notes = "Returns the height of the map." },
|
||||||
|
GetID = { Params = "", Return = "number", Notes = "Returns the numerical ID of the map. (The item damage value)" },
|
||||||
|
GetName = { Params = "", Return = "string", Notes = "Returns the name of the map." },
|
||||||
|
GetNumPixels = { Params = "", Return = "number", Notes = "Returns the number of pixels in this map." },
|
||||||
|
GetPixel = { Params = "PixelX, PixelZ", Return = "ColorID", Notes = "Returns the color of the specified pixel." },
|
||||||
|
GetPixelWidth = { Params = "", Return = "number", Notes = "Returns the width of a single pixel in blocks." },
|
||||||
|
GetScale = { Params = "", Return = "number", Notes = "Returns the scale of the map. Range: [0,4]" },
|
||||||
|
GetWidth = { Params = "", Return = "number", Notes = "Returns the width of the map." },
|
||||||
|
GetWorld = { Params = "", Return = "cWorld", Notes = "Returns the associated world." },
|
||||||
|
Resize = { Params = "Width, Height", Return = "", Notes = "Resizes the map. WARNING: This will erase the pixel data." },
|
||||||
|
SetPixel = { Params = "PixelX, PixelZ, ColorID", Return = "bool", Notes = "Sets the color of the specified pixel. Returns false on error (Out of range)." },
|
||||||
|
SetPosition = { Params = "CenterX, CenterZ", Return = "", Notes = "Relocates the map. The pixel data will not be modified." },
|
||||||
|
SetScale = { Params = "number", Return = "", Notes = "Rescales the map. The pixel data will not be modified." },
|
||||||
|
},
|
||||||
|
Constants =
|
||||||
|
{
|
||||||
|
E_BASE_COLOR_BLUE = { Notes = "" },
|
||||||
|
E_BASE_COLOR_BROWN = { Notes = "" },
|
||||||
|
E_BASE_COLOR_DARK_BROWN = { Notes = "" },
|
||||||
|
E_BASE_COLOR_DARK_GRAY = { Notes = "" },
|
||||||
|
E_BASE_COLOR_DARK_GREEN = { Notes = "" },
|
||||||
|
E_BASE_COLOR_GRAY_1 = { Notes = "" },
|
||||||
|
E_BASE_COLOR_GRAY_2 = { Notes = "" },
|
||||||
|
E_BASE_COLOR_LIGHT_BROWN = { Notes = "" },
|
||||||
|
E_BASE_COLOR_LIGHT_GRAY = { Notes = "" },
|
||||||
|
E_BASE_COLOR_LIGHT_GREEN = { Notes = "" },
|
||||||
|
E_BASE_COLOR_PALE_BLUE = { Notes = "" },
|
||||||
|
E_BASE_COLOR_RED = { Notes = "" },
|
||||||
|
E_BASE_COLOR_TRANSPARENT = { Notes = "" },
|
||||||
|
E_BASE_COLOR_WHITE = { Notes = "" },
|
||||||
|
},
|
||||||
|
}, -- cMap
|
||||||
|
|
||||||
|
cMapManager =
|
||||||
|
{
|
||||||
|
Desc = [[
|
||||||
|
This class is associated with a single {{cWorld}} instance and manages a list of maps.
|
||||||
|
]],
|
||||||
|
Functions =
|
||||||
|
{
|
||||||
|
DoWithMap = { Params = "ID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If a map with the specified ID exists, calls the CallbackFunction for that map. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMap|Map}}, [CallbackData])</pre> Returns true if the map was found and the callback called, false if map not found." },
|
||||||
|
GetNumMaps = { Params = "", Return = "number", Notes = "Returns the number of registered maps." },
|
||||||
|
},
|
||||||
|
|
||||||
|
}, -- cMapManager
|
||||||
|
|
||||||
cMonster =
|
cMonster =
|
||||||
{
|
{
|
||||||
Desc = [[
|
Desc = [[
|
||||||
@ -2107,7 +2169,8 @@ end
|
|||||||
GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." },
|
GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." },
|
||||||
GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. <b>WARNING</b>: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" },
|
GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. <b>WARNING</b>: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" },
|
||||||
GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." },
|
GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." },
|
||||||
GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
|
GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
|
||||||
|
GetMapManager = { Params = "", Return = "{{cMapManager}}", Notes = "Returns the {{cMapManager|MapManager}} object used by this world." },
|
||||||
GetMaxCactusHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which cacti will grow naturally." },
|
GetMaxCactusHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which cacti will grow naturally." },
|
||||||
GetMaxSugarcaneHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which sugarcane will grow naturally." },
|
GetMaxSugarcaneHeight = { Params = "", Return = "number", Notes = "Returns the configured maximum height to which sugarcane will grow naturally." },
|
||||||
GetName = { Params = "", Return = "string", Notes = "Returns the name of the world, as specified in the settings.ini file." },
|
GetName = { Params = "", Return = "string", Notes = "Returns the name of the world, as specified in the settings.ini file." },
|
||||||
|
@ -156,7 +156,7 @@ Lighter = IronIngot, 1:1 | Flint, 2:2
|
|||||||
Lighter = IronIngot, 2:1 | Flint, 1:2
|
Lighter = IronIngot, 2:1 | Flint, 1:2
|
||||||
Bucket = IronIngot, 1:1, 2:2, 3:1
|
Bucket = IronIngot, 1:1, 2:2, 3:1
|
||||||
Compass = IronIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
|
Compass = IronIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
|
||||||
Map = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
|
EmptyMap = Paper, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Compass, 2:2
|
||||||
Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
|
Watch = GoldIngot, 2:1, 1:2, 3:2, 2:3 | RedstoneDust, 2:2
|
||||||
FishingRod = Stick, 1:3, 2:2, 3:1 | String, 3:2, 3:3
|
FishingRod = Stick, 1:3, 2:2, 3:1 | String, 3:2, 3:3
|
||||||
FishingRod = Stick, 3:3, 2:2, 1:1 | String, 1:2, 1:3
|
FishingRod = Stick, 3:3, 2:2, 1:1 | String, 1:2, 1:3
|
||||||
|
@ -48,6 +48,7 @@ $cfile "../ItemGrid.h"
|
|||||||
$cfile "../BlockEntities/BlockEntity.h"
|
$cfile "../BlockEntities/BlockEntity.h"
|
||||||
$cfile "../BlockEntities/BlockEntityWithItems.h"
|
$cfile "../BlockEntities/BlockEntityWithItems.h"
|
||||||
$cfile "../BlockEntities/ChestEntity.h"
|
$cfile "../BlockEntities/ChestEntity.h"
|
||||||
|
$cfile "../BlockEntities/CommandBlockEntity.h"
|
||||||
$cfile "../BlockEntities/DropSpenserEntity.h"
|
$cfile "../BlockEntities/DropSpenserEntity.h"
|
||||||
$cfile "../BlockEntities/DispenserEntity.h"
|
$cfile "../BlockEntities/DispenserEntity.h"
|
||||||
$cfile "../BlockEntities/DropperEntity.h"
|
$cfile "../BlockEntities/DropperEntity.h"
|
||||||
@ -72,6 +73,8 @@ $cfile "../CraftingRecipes.h"
|
|||||||
$cfile "../UI/Window.h"
|
$cfile "../UI/Window.h"
|
||||||
$cfile "../Mobs/Monster.h"
|
$cfile "../Mobs/Monster.h"
|
||||||
$cfile "../CompositeChat.h"
|
$cfile "../CompositeChat.h"
|
||||||
|
$cfile "../Map.h"
|
||||||
|
$cfile "../MapManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2575,6 +2575,10 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
|||||||
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
|
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
|
tolua_beginmodule(tolua_S, "cMapManager");
|
||||||
|
tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
|
||||||
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cPlugin");
|
tolua_beginmodule(tolua_S, "cPlugin");
|
||||||
tolua_function(tolua_S, "Call", tolua_cPlugin_Call);
|
tolua_function(tolua_S, "Call", tolua_cPlugin_Call);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
@ -2142,6 +2142,33 @@ void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cI
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||||
|
{
|
||||||
|
m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
|
||||||
|
{
|
||||||
|
m_Protocol->SendMapDecorators(a_ID, a_Decorators);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||||
|
{
|
||||||
|
m_Protocol->SendMapInfo(a_ID, a_Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
void cClientHandle::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
{
|
{
|
||||||
m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
|
m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "ChunkDef.h"
|
#include "ChunkDef.h"
|
||||||
#include "ByteBuffer.h"
|
#include "ByteBuffer.h"
|
||||||
#include "Scoreboard.h"
|
#include "Scoreboard.h"
|
||||||
|
#include "Map.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +113,9 @@ public:
|
|||||||
void SendGameMode (eGameMode a_GameMode);
|
void SendGameMode (eGameMode a_GameMode);
|
||||||
void SendHealth (void);
|
void SendHealth (void);
|
||||||
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
|
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
|
||||||
|
void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length);
|
||||||
|
void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators);
|
||||||
|
void SendMapInfo (int a_ID, unsigned int a_Scale);
|
||||||
void SendPaintingSpawn (const cPainting & a_Painting);
|
void SendPaintingSpawn (const cPainting & a_Painting);
|
||||||
void SendPickupSpawn (const cPickup & a_Pickup);
|
void SendPickupSpawn (const cPickup & a_Pickup);
|
||||||
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
|
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
|
||||||
|
@ -254,6 +254,9 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
HandleFloater();
|
HandleFloater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update items (e.g. Maps)
|
||||||
|
m_Inventory.UpdateItems();
|
||||||
|
|
||||||
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
|
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
|
||||||
cTimer t1;
|
cTimer t1;
|
||||||
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
|
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
|
||||||
|
@ -51,15 +51,6 @@ const int NEST_SIZE_GRAVEL = 32;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T> T Clamp(T a_Value, T a_Min, T a_Max)
|
|
||||||
{
|
|
||||||
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cStructGenTrees:
|
// cStructGenTrees:
|
||||||
|
|
||||||
|
@ -235,6 +235,16 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Clamp X to the specified range. */
|
||||||
|
template <typename T>
|
||||||
|
T Clamp(T a_Value, T a_Min, T a_Max)
|
||||||
|
{
|
||||||
|
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Common headers (part 2, with macros):
|
// Common headers (part 2, with macros):
|
||||||
#include "ChunkDef.h"
|
#include "ChunkDef.h"
|
||||||
|
@ -515,6 +515,31 @@ bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cInventory::UpdateItems(void)
|
||||||
|
{
|
||||||
|
const cItem & Slot = GetEquippedItem();
|
||||||
|
|
||||||
|
if (Slot.IsEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Slot.m_ItemType)
|
||||||
|
{
|
||||||
|
case E_ITEM_MAP:
|
||||||
|
{
|
||||||
|
ItemHandler(Slot.m_ItemType)->OnUpdate(m_Owner.GetWorld(), &m_Owner, Slot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cInventory::SaveToJson(Json::Value & a_Value)
|
void cInventory::SaveToJson(Json::Value & a_Value)
|
||||||
{
|
{
|
||||||
// The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
|
// The JSON originally included the 4 crafting slots and the result, so we have to put empty items there, too:
|
||||||
|
@ -150,6 +150,9 @@ public:
|
|||||||
/// Sends the slot contents to the owner
|
/// Sends the slot contents to the owner
|
||||||
void SendSlot(int a_SlotNum);
|
void SendSlot(int a_SlotNum);
|
||||||
|
|
||||||
|
/// Update items (e.g. Maps)
|
||||||
|
void UpdateItems(void);
|
||||||
|
|
||||||
/// Converts an armor slot number into the ID for the EntityEquipment packet
|
/// Converts an armor slot number into the ID for the EntityEquipment packet
|
||||||
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
|
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
|
||||||
|
|
||||||
|
62
src/Items/ItemEmptyMap.h
Normal file
62
src/Items/ItemEmptyMap.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
// ItemEmptyMap.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Entities/Entity.h"
|
||||||
|
#include "../Item.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cItemEmptyMapHandler :
|
||||||
|
public cItemHandler
|
||||||
|
{
|
||||||
|
typedef cItemHandler super;
|
||||||
|
|
||||||
|
static const unsigned int DEFAULT_SCALE = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cItemEmptyMapHandler() :
|
||||||
|
super(E_ITEM_EMPTY_MAP)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
|
||||||
|
{
|
||||||
|
UNUSED(a_Item);
|
||||||
|
UNUSED(a_BlockX);
|
||||||
|
UNUSED(a_BlockZ);
|
||||||
|
UNUSED(a_Dir);
|
||||||
|
|
||||||
|
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
|
||||||
|
|
||||||
|
const int RegionWidth = cChunkDef::Width * 8 * pow(2, DEFAULT_SCALE);
|
||||||
|
|
||||||
|
int CenterX = round(a_Player->GetPosX() / (float) RegionWidth) * RegionWidth;
|
||||||
|
int CenterZ = round(a_Player->GetPosZ() / (float) RegionWidth) * RegionWidth;
|
||||||
|
|
||||||
|
cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
|
||||||
|
|
||||||
|
// Remove empty map from inventory
|
||||||
|
if (!a_Player->GetInventory().RemoveOneEquippedItem())
|
||||||
|
{
|
||||||
|
ASSERT(!"Inventory mismatch");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NewMap == NULL)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, NewMap->GetID()), true, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} ;
|
@ -18,6 +18,7 @@
|
|||||||
#include "ItemComparator.h"
|
#include "ItemComparator.h"
|
||||||
#include "ItemDoor.h"
|
#include "ItemDoor.h"
|
||||||
#include "ItemDye.h"
|
#include "ItemDye.h"
|
||||||
|
#include "ItemEmptyMap.h"
|
||||||
#include "ItemFishingRod.h"
|
#include "ItemFishingRod.h"
|
||||||
#include "ItemFlowerPot.h"
|
#include "ItemFlowerPot.h"
|
||||||
#include "ItemFood.h"
|
#include "ItemFood.h"
|
||||||
@ -25,6 +26,7 @@
|
|||||||
#include "ItemHoe.h"
|
#include "ItemHoe.h"
|
||||||
#include "ItemLeaves.h"
|
#include "ItemLeaves.h"
|
||||||
#include "ItemLighter.h"
|
#include "ItemLighter.h"
|
||||||
|
#include "ItemMap.h"
|
||||||
#include "ItemMinecart.h"
|
#include "ItemMinecart.h"
|
||||||
#include "ItemNetherWart.h"
|
#include "ItemNetherWart.h"
|
||||||
#include "ItemPainting.h"
|
#include "ItemPainting.h"
|
||||||
@ -103,11 +105,13 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
|
|||||||
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
|
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
|
||||||
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
|
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
|
||||||
case E_ITEM_EGG: return new cItemEggHandler();
|
case E_ITEM_EGG: return new cItemEggHandler();
|
||||||
|
case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
|
||||||
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
|
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
|
||||||
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
|
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
|
||||||
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
|
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
|
||||||
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
|
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
|
||||||
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
|
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
|
||||||
|
case E_ITEM_MAP: return new cItemMapHandler();
|
||||||
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
|
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
|
||||||
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
|
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
|
||||||
case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
|
case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
|
||||||
|
@ -32,6 +32,14 @@ public:
|
|||||||
UNUSED(a_BlockZ);
|
UNUSED(a_BlockZ);
|
||||||
UNUSED(a_BlockFace);
|
UNUSED(a_BlockFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items
|
||||||
|
virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
|
||||||
|
{
|
||||||
|
UNUSED(a_World);
|
||||||
|
UNUSED(a_Player);
|
||||||
|
UNUSED(a_Item);
|
||||||
|
}
|
||||||
|
|
||||||
/// Called while the player diggs a block using this item
|
/// Called while the player diggs a block using this item
|
||||||
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
|
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
|
||||||
|
43
src/Items/ItemMap.h
Normal file
43
src/Items/ItemMap.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
// ItemMap.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Entities/Entity.h"
|
||||||
|
#include "../Item.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cItemMapHandler :
|
||||||
|
public cItemHandler
|
||||||
|
{
|
||||||
|
typedef cItemHandler super;
|
||||||
|
|
||||||
|
static const unsigned int DEFAULT_RADIUS = 128;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cItemMapHandler() :
|
||||||
|
super(E_ITEM_MAP)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item)
|
||||||
|
{
|
||||||
|
cMap * Map = a_World->GetMapManager().GetMapData(a_Item.m_ItemDamage);
|
||||||
|
|
||||||
|
if (Map == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map->UpdateRadius(*a_Player, DEFAULT_RADIUS);
|
||||||
|
|
||||||
|
Map->UpdateClient(a_Player);
|
||||||
|
}
|
||||||
|
} ;
|
629
src/Map.cpp
Normal file
629
src/Map.cpp
Normal file
@ -0,0 +1,629 @@
|
|||||||
|
|
||||||
|
// Map.cpp
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "Map.h"
|
||||||
|
|
||||||
|
#include "ClientHandle.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "Chunk.h"
|
||||||
|
#include "Entities/Player.h"
|
||||||
|
#include "FastRandom.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMapDecorator::cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, int a_Rot)
|
||||||
|
: m_Map(a_Map)
|
||||||
|
, m_Type(a_Type)
|
||||||
|
, m_PixelX(a_X)
|
||||||
|
, m_PixelZ(a_Z)
|
||||||
|
, m_Rot(a_Rot)
|
||||||
|
, m_Player(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMapDecorator::cMapDecorator(cMap * a_Map, cPlayer * a_Player)
|
||||||
|
: m_Map(a_Map)
|
||||||
|
, m_Type(E_TYPE_PLAYER)
|
||||||
|
, m_Player(a_Player)
|
||||||
|
{
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMapDecorator::Update(void)
|
||||||
|
{
|
||||||
|
if (m_Player != NULL)
|
||||||
|
{
|
||||||
|
ASSERT(m_Map != NULL);
|
||||||
|
unsigned int PixelWidth = m_Map->GetPixelWidth();
|
||||||
|
|
||||||
|
int InsideWidth = (m_Map->GetWidth() / 2) - 1;
|
||||||
|
int InsideHeight = (m_Map->GetHeight() / 2) - 1;
|
||||||
|
|
||||||
|
int PixelX = (m_Player->GetPosX() - m_Map->GetCenterX()) / PixelWidth;
|
||||||
|
int PixelZ = (m_Player->GetPosZ() - m_Map->GetCenterZ()) / PixelWidth;
|
||||||
|
|
||||||
|
// Center of pixel
|
||||||
|
m_PixelX = (2 * PixelX) + 1;
|
||||||
|
m_PixelZ = (2 * PixelZ) + 1;
|
||||||
|
|
||||||
|
if ((PixelX > -InsideWidth) && (PixelX <= InsideWidth) && (PixelZ > -InsideHeight) && (PixelZ <= InsideHeight))
|
||||||
|
{
|
||||||
|
double Yaw = m_Player->GetYaw();
|
||||||
|
|
||||||
|
if (m_Map->GetDimension() == dimNether)
|
||||||
|
{
|
||||||
|
cFastRandom Random;
|
||||||
|
|
||||||
|
Int64 WorldAge = m_Player->GetWorld()->GetWorldAge();
|
||||||
|
|
||||||
|
// TODO 2014-02-19 xdot: Refine
|
||||||
|
m_Rot = Random.NextInt(16, WorldAge);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_Rot = (Yaw * 16) / 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Type = E_TYPE_PLAYER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((abs(PixelX) > 320.0) || (abs(PixelZ) > 320.0))
|
||||||
|
{
|
||||||
|
// TODO 2014-02-18 xdot: Remove decorator
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Rot = 0;
|
||||||
|
|
||||||
|
m_Type = E_TYPE_PLAYER_OUTSIDE;
|
||||||
|
|
||||||
|
// Move to border
|
||||||
|
if (PixelX <= -InsideWidth)
|
||||||
|
{
|
||||||
|
m_PixelX = (2 * -InsideWidth) + 1;
|
||||||
|
}
|
||||||
|
if (PixelZ <= -InsideHeight)
|
||||||
|
{
|
||||||
|
m_PixelZ = (2 * -InsideHeight) + 1;
|
||||||
|
}
|
||||||
|
if (PixelX > InsideWidth)
|
||||||
|
{
|
||||||
|
m_PixelX = (2 * InsideWidth) + 1;
|
||||||
|
}
|
||||||
|
if (PixelZ > InsideHeight)
|
||||||
|
{
|
||||||
|
m_PixelZ = (2 * InsideHeight) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMap::cMap(unsigned int a_ID, cWorld * a_World)
|
||||||
|
: m_ID(a_ID)
|
||||||
|
, m_Width(cChunkDef::Width * 8)
|
||||||
|
, m_Height(cChunkDef::Width * 8)
|
||||||
|
, m_Scale(3)
|
||||||
|
, m_CenterX(0)
|
||||||
|
, m_CenterZ(0)
|
||||||
|
, m_World(a_World)
|
||||||
|
{
|
||||||
|
m_Data.assign(m_Width * m_Height, E_BASE_COLOR_TRANSPARENT);
|
||||||
|
|
||||||
|
Printf(m_Name, "map_%i", m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale)
|
||||||
|
: m_ID(a_ID)
|
||||||
|
, m_Width(cChunkDef::Width * 8)
|
||||||
|
, m_Height(cChunkDef::Width * 8)
|
||||||
|
, m_Scale(a_Scale)
|
||||||
|
, m_CenterX(a_CenterX)
|
||||||
|
, m_CenterZ(a_CenterZ)
|
||||||
|
, m_World(a_World)
|
||||||
|
{
|
||||||
|
m_Data.assign(m_Width * m_Height, E_BASE_COLOR_TRANSPARENT);
|
||||||
|
|
||||||
|
Printf(m_Name, "map_%i", m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius)
|
||||||
|
{
|
||||||
|
int PixelRadius = a_Radius / GetPixelWidth();
|
||||||
|
|
||||||
|
unsigned int StartX = Clamp(a_PixelX - PixelRadius, 0, (int)m_Width);
|
||||||
|
unsigned int StartZ = Clamp(a_PixelZ - PixelRadius, 0, (int)m_Height);
|
||||||
|
|
||||||
|
unsigned int EndX = Clamp(a_PixelX + PixelRadius, 0, (int)m_Width);
|
||||||
|
unsigned int EndZ = Clamp(a_PixelZ + PixelRadius, 0, (int)m_Height);
|
||||||
|
|
||||||
|
for (unsigned int X = StartX; X < EndX; ++X)
|
||||||
|
{
|
||||||
|
for (unsigned int Z = StartZ; Z < EndZ; ++Z)
|
||||||
|
{
|
||||||
|
int dX = X - a_PixelX;
|
||||||
|
int dZ = Z - a_PixelZ;
|
||||||
|
|
||||||
|
if ((dX * dX) + (dZ * dZ) < (PixelRadius * PixelRadius))
|
||||||
|
{
|
||||||
|
UpdatePixel(X, Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
|
||||||
|
{
|
||||||
|
unsigned int PixelWidth = GetPixelWidth();
|
||||||
|
|
||||||
|
int PixelX = (a_Player.GetPosX() - m_CenterX) / PixelWidth + (m_Width / 2);
|
||||||
|
int PixelZ = (a_Player.GetPosZ() - m_CenterZ) / PixelWidth + (m_Height / 2);
|
||||||
|
|
||||||
|
UpdateRadius(PixelX, PixelZ, a_Radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
|
||||||
|
{
|
||||||
|
unsigned int PixelWidth = GetPixelWidth();
|
||||||
|
|
||||||
|
int BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth);
|
||||||
|
int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
|
||||||
|
|
||||||
|
int ChunkX, ChunkY, ChunkZ;
|
||||||
|
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ);
|
||||||
|
|
||||||
|
int RelX = BlockX - (ChunkX * cChunkDef::Width);
|
||||||
|
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);
|
||||||
|
|
||||||
|
class cCalculatePixelCb :
|
||||||
|
public cChunkCallback
|
||||||
|
{
|
||||||
|
cMap * m_Map;
|
||||||
|
|
||||||
|
int m_RelX, m_RelZ;
|
||||||
|
|
||||||
|
ColorID m_PixelData;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cCalculatePixelCb(cMap * a_Map, int a_RelX, int a_RelZ)
|
||||||
|
: m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(E_BASE_COLOR_TRANSPARENT) {}
|
||||||
|
|
||||||
|
virtual bool Item(cChunk * a_Chunk) override
|
||||||
|
{
|
||||||
|
if (a_Chunk == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int PixelWidth = m_Map->GetPixelWidth();
|
||||||
|
|
||||||
|
if (m_Map->GetDimension() == dimNether)
|
||||||
|
{
|
||||||
|
// TODO 2014-02-22 xdot: Nether maps
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::map<ColorID, unsigned int> ColorCountMap;
|
||||||
|
ColorCountMap ColorCounts;
|
||||||
|
|
||||||
|
// Count surface blocks
|
||||||
|
for (unsigned int X = m_RelX; X < m_RelX + PixelWidth; ++X)
|
||||||
|
{
|
||||||
|
for (unsigned int Z = m_RelZ; Z < m_RelZ + PixelWidth; ++Z)
|
||||||
|
{
|
||||||
|
unsigned int WaterDepth = 0;
|
||||||
|
|
||||||
|
BLOCKTYPE TargetBlock = E_BLOCK_AIR;
|
||||||
|
NIBBLETYPE TargetMeta = 0;
|
||||||
|
|
||||||
|
int Height = a_Chunk->GetHeight(X, Z);
|
||||||
|
|
||||||
|
while (Height > 0)
|
||||||
|
{
|
||||||
|
a_Chunk->GetBlockTypeMeta(X, Height, Z, TargetBlock, TargetMeta);
|
||||||
|
|
||||||
|
// TODO 2014-02-22 xdot: Check if block color is transparent
|
||||||
|
if (TargetBlock == E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
--Height;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO 2014-02-22 xdot: Check if block is liquid
|
||||||
|
else if (false)
|
||||||
|
{
|
||||||
|
--Height;
|
||||||
|
++WaterDepth;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 2014-02-22 xdot: Query block color
|
||||||
|
ColorID Color = E_BASE_COLOR_BROWN;
|
||||||
|
|
||||||
|
// Debug - Temporary
|
||||||
|
switch (TargetBlock)
|
||||||
|
{
|
||||||
|
case E_BLOCK_GRASS:
|
||||||
|
{
|
||||||
|
Color = E_BASE_COLOR_LIGHT_GREEN; break;
|
||||||
|
}
|
||||||
|
case E_BLOCK_STATIONARY_WATER:
|
||||||
|
case E_BLOCK_WATER:
|
||||||
|
{
|
||||||
|
Color = E_BASE_COLOR_BLUE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++ColorCounts[Color];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find dominant color
|
||||||
|
ColorID PixelColor = E_BASE_COLOR_TRANSPARENT;
|
||||||
|
|
||||||
|
unsigned int MaxCount = 0;
|
||||||
|
|
||||||
|
for (ColorCountMap::iterator it = ColorCounts.begin(); it != ColorCounts.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second > MaxCount)
|
||||||
|
{
|
||||||
|
PixelColor = it->first;
|
||||||
|
MaxCount = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 2014-02-22 xdot: Adjust brightness
|
||||||
|
unsigned int dColor = 1;
|
||||||
|
|
||||||
|
m_PixelData = PixelColor + dColor;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorID GetPixelData(void) const
|
||||||
|
{
|
||||||
|
return m_PixelData;
|
||||||
|
}
|
||||||
|
} CalculatePixelCb(this, RelX, RelZ);
|
||||||
|
|
||||||
|
ASSERT(m_World != NULL);
|
||||||
|
m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
|
||||||
|
|
||||||
|
SetPixel(a_X, a_Z, CalculatePixelCb.GetPixelData());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::UpdateDecorators(void)
|
||||||
|
{
|
||||||
|
for (cMapDecoratorList::iterator it = m_Decorators.begin(); it != m_Decorators.end(); ++it)
|
||||||
|
{
|
||||||
|
it->Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::AddPlayer(cPlayer * a_Player, Int64 a_WorldAge)
|
||||||
|
{
|
||||||
|
cClientHandle * Handle = a_Player->GetClientHandle();
|
||||||
|
if (Handle == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMapClient MapClient;
|
||||||
|
|
||||||
|
MapClient.m_LastUpdate = a_WorldAge;
|
||||||
|
MapClient.m_SendInfo = true;
|
||||||
|
MapClient.m_Handle = Handle;
|
||||||
|
|
||||||
|
m_Clients.push_back(MapClient);
|
||||||
|
|
||||||
|
cMapDecorator PlayerDecorator(this, a_Player);
|
||||||
|
|
||||||
|
m_Decorators.push_back(PlayerDecorator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::RemoveInactiveClients(Int64 a_WorldAge)
|
||||||
|
{
|
||||||
|
for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end();)
|
||||||
|
{
|
||||||
|
if (it->m_LastUpdate < a_WorldAge)
|
||||||
|
{
|
||||||
|
// Remove associated decorators
|
||||||
|
for (cMapDecoratorList::iterator it2 = m_Decorators.begin(); it2 != m_Decorators.end();)
|
||||||
|
{
|
||||||
|
if (it2->GetPlayer()->GetClientHandle() == it->m_Handle)
|
||||||
|
{
|
||||||
|
// Erase decorator
|
||||||
|
cMapDecoratorList::iterator temp = it2;
|
||||||
|
++it2;
|
||||||
|
m_Decorators.erase(temp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase client
|
||||||
|
cMapClientList::iterator temp = it;
|
||||||
|
++it;
|
||||||
|
m_Clients.erase(temp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::StreamNext(cMapClient & a_Client)
|
||||||
|
{
|
||||||
|
cClientHandle * Handle = a_Client.m_Handle;
|
||||||
|
|
||||||
|
if (a_Client.m_SendInfo)
|
||||||
|
{
|
||||||
|
Handle->SendMapInfo(m_ID, m_Scale);
|
||||||
|
|
||||||
|
a_Client.m_SendInfo = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++a_Client.m_NextDecoratorUpdate;
|
||||||
|
|
||||||
|
if (a_Client.m_NextDecoratorUpdate >= 4)
|
||||||
|
{
|
||||||
|
// TODO 2014-02-19 xdot
|
||||||
|
// This is dangerous as the player object may have been destroyed before the decorator is erased from the list
|
||||||
|
UpdateDecorators();
|
||||||
|
|
||||||
|
Handle->SendMapDecorators(m_ID, m_Decorators);
|
||||||
|
|
||||||
|
a_Client.m_NextDecoratorUpdate = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++a_Client.m_DataUpdate;
|
||||||
|
|
||||||
|
unsigned int Y = (a_Client.m_DataUpdate * 11) % m_Width;
|
||||||
|
|
||||||
|
const Byte * Colors = &m_Data[Y * m_Height];
|
||||||
|
|
||||||
|
Handle->SendMapColumn(m_ID, Y, 0, Colors, m_Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::UpdateClient(cPlayer * a_Player)
|
||||||
|
{
|
||||||
|
ASSERT(a_Player != NULL);
|
||||||
|
cClientHandle * Handle = a_Player->GetClientHandle();
|
||||||
|
|
||||||
|
if (Handle == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64 WorldAge = a_Player->GetWorld()->GetWorldAge();
|
||||||
|
|
||||||
|
RemoveInactiveClients(WorldAge - 5);
|
||||||
|
|
||||||
|
// Linear search for client state
|
||||||
|
for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->m_Handle == Handle)
|
||||||
|
{
|
||||||
|
it->m_LastUpdate = WorldAge;
|
||||||
|
|
||||||
|
StreamNext(*it);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New player, construct a new client state
|
||||||
|
AddPlayer(a_Player, WorldAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::EraseData(void)
|
||||||
|
{
|
||||||
|
m_Data.assign(m_Width * m_Height, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
eDimension cMap::GetDimension(void) const
|
||||||
|
{
|
||||||
|
ASSERT(m_World != NULL);
|
||||||
|
return m_World->GetDimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::Resize(unsigned int a_Width, unsigned int a_Height)
|
||||||
|
{
|
||||||
|
if ((m_Width == a_Width) && (m_Height == a_Height))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Width = a_Width;
|
||||||
|
m_Height = a_Height;
|
||||||
|
|
||||||
|
m_Data.assign(m_Width * m_Height, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::SetPosition(int a_CenterX, int a_CenterZ)
|
||||||
|
{
|
||||||
|
m_CenterX = a_CenterX;
|
||||||
|
m_CenterZ = a_CenterZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::SetScale(unsigned int a_Scale)
|
||||||
|
{
|
||||||
|
if (m_Scale == a_Scale)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Scale = a_Scale;
|
||||||
|
|
||||||
|
for (cMapClientList::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
|
||||||
|
{
|
||||||
|
it->m_SendInfo = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMap::SetPixel(unsigned int a_X, unsigned int a_Z, cMap::ColorID a_Data)
|
||||||
|
{
|
||||||
|
if ((a_X < m_Width) && (a_Z < m_Height))
|
||||||
|
{
|
||||||
|
m_Data[a_Z + (a_X * m_Height)] = a_Data;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMap::ColorID cMap::GetPixel(unsigned int a_X, unsigned int a_Z)
|
||||||
|
{
|
||||||
|
if ((a_X < m_Width) && (a_Z < m_Height))
|
||||||
|
{
|
||||||
|
return m_Data[a_Z + (a_X * m_Height)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return E_BASE_COLOR_TRANSPARENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMap::SendTo(cClientHandle & a_Client)
|
||||||
|
{
|
||||||
|
a_Client.SendMapInfo(m_ID, m_Scale);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < m_Width; ++i)
|
||||||
|
{
|
||||||
|
const Byte* Colors = &m_Data[i * m_Height];
|
||||||
|
|
||||||
|
a_Client.SendMapColumn(m_ID, i, 0, Colors, m_Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Client.SendMapDecorators(m_ID, m_Decorators);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cMap::GetNumPixels(void) const
|
||||||
|
{
|
||||||
|
return m_Width * m_Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cMap::GetNumDecorators(void) const
|
||||||
|
{
|
||||||
|
return m_Decorators.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cMap::GetPixelWidth(void) const
|
||||||
|
{
|
||||||
|
return pow(2, m_Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
264
src/Map.h
Normal file
264
src/Map.h
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
|
||||||
|
// Map.h
|
||||||
|
|
||||||
|
// Implementation of in-game coloured maps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cClientHandle;
|
||||||
|
class cWorld;
|
||||||
|
class cPlayer;
|
||||||
|
class cMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Encapsulates a map decorator.
|
||||||
|
*
|
||||||
|
* A map decorator represents an object drawn on the map that can move freely.
|
||||||
|
* (e.g. player trackers and item frame pointers)
|
||||||
|
*
|
||||||
|
* Excluding manually placed decorators,
|
||||||
|
* decorators are automatically managed (allocated and freed) by their parent cMap instance.
|
||||||
|
*/
|
||||||
|
class cMapDecorator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum eType
|
||||||
|
{
|
||||||
|
E_TYPE_PLAYER = 0x00,
|
||||||
|
E_TYPE_ITEM_FRAME = 0x01,
|
||||||
|
|
||||||
|
/** Player outside of the boundaries of the map. */
|
||||||
|
E_TYPE_PLAYER_OUTSIDE = 0x06
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Constructs a map decorator fixed at the specified pixel coordinates. (DEBUG) */
|
||||||
|
cMapDecorator(cMap * a_Map, eType a_Type, int a_X, int a_Z, int a_Rot);
|
||||||
|
|
||||||
|
/** Constructs a map decorator that tracks a player. */
|
||||||
|
cMapDecorator(cMap * a_Map, cPlayer * a_Player);
|
||||||
|
|
||||||
|
/** Updates the decorator. */
|
||||||
|
void Update(void);
|
||||||
|
|
||||||
|
unsigned int GetPixelX(void) const { return m_PixelX; }
|
||||||
|
unsigned int GetPixelZ(void) const { return m_PixelZ; }
|
||||||
|
|
||||||
|
int GetRot(void) const { return m_Rot; }
|
||||||
|
|
||||||
|
eType GetType(void) const { return m_Type; }
|
||||||
|
|
||||||
|
cPlayer * GetPlayer(void) { return m_Player; }
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
cMap * m_Map;
|
||||||
|
|
||||||
|
eType m_Type;
|
||||||
|
|
||||||
|
unsigned int m_PixelX;
|
||||||
|
unsigned int m_PixelZ;
|
||||||
|
|
||||||
|
unsigned int m_Rot;
|
||||||
|
|
||||||
|
cPlayer * m_Player;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<cMapDecorator> cMapDecoratorList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/** Encapsulates an in-game world map. */
|
||||||
|
class cMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum eBaseColor
|
||||||
|
{
|
||||||
|
E_BASE_COLOR_TRANSPARENT = 0, /* Air */
|
||||||
|
E_BASE_COLOR_LIGHT_GREEN = 4, /* Grass */
|
||||||
|
E_BASE_COLOR_LIGHT_BROWN = 8, /* Sand */
|
||||||
|
E_BASE_COLOR_GRAY_1 = 12, /* Cloth */
|
||||||
|
E_BASE_COLOR_RED = 16, /* TNT */
|
||||||
|
E_BASE_COLOR_PALE_BLUE = 20, /* Ice */
|
||||||
|
E_BASE_COLOR_GRAY_2 = 24, /* Iron */
|
||||||
|
E_BASE_COLOR_DARK_GREEN = 28, /* Foliage */
|
||||||
|
E_BASE_COLOR_WHITE = 32, /* Snow */
|
||||||
|
E_BASE_COLOR_LIGHT_GRAY = 36, /* Clay */
|
||||||
|
E_BASE_COLOR_BROWN = 40, /* Dirt */
|
||||||
|
E_BASE_COLOR_DARK_GRAY = 44, /* Stone */
|
||||||
|
E_BASE_COLOR_BLUE = 48, /* Water */
|
||||||
|
E_BASE_COLOR_DARK_BROWN = 52 /* Wood */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Byte ColorID;
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
typedef std::vector<ColorID> cColorList;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Construct an empty map. */
|
||||||
|
cMap(unsigned int a_ID, cWorld * a_World);
|
||||||
|
|
||||||
|
/** Construct an empty map at the specified coordinates. */
|
||||||
|
cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale = 3);
|
||||||
|
|
||||||
|
/** Send this map to the specified client. WARNING: Slow */
|
||||||
|
void SendTo(cClientHandle & a_Client);
|
||||||
|
|
||||||
|
/** Update a circular region with the specified radius and center (in pixels). */
|
||||||
|
void UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius);
|
||||||
|
|
||||||
|
/** Update a circular region around the specified player. */
|
||||||
|
void UpdateRadius(cPlayer & a_Player, unsigned int a_Radius);
|
||||||
|
|
||||||
|
/** Send next update packet to the specified player and remove invalid decorators/clients. */
|
||||||
|
void UpdateClient(cPlayer * a_Player);
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/** Erase pixel data */
|
||||||
|
void EraseData(void);
|
||||||
|
|
||||||
|
void Resize(unsigned int a_Width, unsigned int a_Height);
|
||||||
|
|
||||||
|
void SetPosition(int a_CenterX, int a_CenterZ);
|
||||||
|
|
||||||
|
void SetScale(unsigned int a_Scale);
|
||||||
|
|
||||||
|
bool SetPixel(unsigned int a_X, unsigned int a_Z, ColorID a_Data);
|
||||||
|
|
||||||
|
ColorID GetPixel(unsigned int a_X, unsigned int a_Z);
|
||||||
|
|
||||||
|
unsigned int GetWidth (void) const { return m_Width; }
|
||||||
|
unsigned int GetHeight(void) const { return m_Height; }
|
||||||
|
|
||||||
|
unsigned int GetScale(void) const { return m_Scale; }
|
||||||
|
|
||||||
|
int GetCenterX(void) const { return m_CenterX; }
|
||||||
|
int GetCenterZ(void) const { return m_CenterZ; }
|
||||||
|
|
||||||
|
unsigned int GetID(void) const { return m_ID; }
|
||||||
|
|
||||||
|
cWorld * GetWorld(void) { return m_World; }
|
||||||
|
|
||||||
|
AString GetName(void) { return m_Name; }
|
||||||
|
|
||||||
|
eDimension GetDimension(void) const;
|
||||||
|
|
||||||
|
unsigned int GetNumPixels(void) const;
|
||||||
|
|
||||||
|
unsigned int GetPixelWidth(void) const;
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
unsigned int GetNumDecorators(void) const;
|
||||||
|
|
||||||
|
const cColorList & GetData(void) const { return m_Data; }
|
||||||
|
|
||||||
|
static const char * GetClassStatic(void) // Needed for ManualBindings's DoWith templates
|
||||||
|
{
|
||||||
|
return "cMap";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Encapsulates the state of a map client.
|
||||||
|
*
|
||||||
|
* In order to enhance performace, maps are streamed column-by-column to each client.
|
||||||
|
* This structure stores the state of the stream.
|
||||||
|
*/
|
||||||
|
struct cMapClient
|
||||||
|
{
|
||||||
|
cClientHandle * m_Handle;
|
||||||
|
|
||||||
|
/** Whether the map scale was modified and needs to be resent. */
|
||||||
|
bool m_SendInfo;
|
||||||
|
|
||||||
|
/** Ticks since last decorator update. */
|
||||||
|
unsigned int m_NextDecoratorUpdate;
|
||||||
|
|
||||||
|
/** Number of pixel data updates. */
|
||||||
|
Int64 m_DataUpdate;
|
||||||
|
|
||||||
|
Int64 m_LastUpdate;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<cMapClient> cMapClientList;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Update the associated decorators. */
|
||||||
|
void UpdateDecorators(void);
|
||||||
|
|
||||||
|
/** Update the specified pixel. */
|
||||||
|
bool UpdatePixel(unsigned int a_X, unsigned int a_Z);
|
||||||
|
|
||||||
|
/** Add a new map client. */
|
||||||
|
void AddPlayer(cPlayer * a_Player, Int64 a_WorldAge);
|
||||||
|
|
||||||
|
/** Remove inactive or invalid clients. */
|
||||||
|
void RemoveInactiveClients(Int64 a_WorldAge);
|
||||||
|
|
||||||
|
/** Send next update packet to the specified client. */
|
||||||
|
void StreamNext(cMapClient & a_Client);
|
||||||
|
|
||||||
|
unsigned int m_ID;
|
||||||
|
|
||||||
|
unsigned int m_Width;
|
||||||
|
unsigned int m_Height;
|
||||||
|
|
||||||
|
/** The zoom level, 2^scale square blocks per pixel */
|
||||||
|
unsigned int m_Scale;
|
||||||
|
|
||||||
|
int m_CenterX;
|
||||||
|
int m_CenterZ;
|
||||||
|
|
||||||
|
/** Column-major array of colours */
|
||||||
|
cColorList m_Data;
|
||||||
|
|
||||||
|
cWorld * m_World;
|
||||||
|
|
||||||
|
cMapDecoratorList m_Decorators;
|
||||||
|
|
||||||
|
cMapClientList m_Clients;
|
||||||
|
|
||||||
|
AString m_Name;
|
||||||
|
|
||||||
|
friend class cMapSerializer;
|
||||||
|
|
||||||
|
}; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
|
178
src/MapManager.cpp
Normal file
178
src/MapManager.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
|
||||||
|
// MapManager.cpp
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "MapManager.h"
|
||||||
|
|
||||||
|
#include "World.h"
|
||||||
|
#include "WorldStorage/MapSerializer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMapManager::cMapManager(cWorld * a_World)
|
||||||
|
: m_World(a_World)
|
||||||
|
{
|
||||||
|
ASSERT(m_World != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMapManager::DoWithMap(int a_ID, cMapCallback & a_Callback)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
cMap * Map = GetMapData(a_ID);
|
||||||
|
|
||||||
|
if (Map == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_Callback.Item(Map);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMapManager::ForEachMap(cMapCallback & a_Callback)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
for (cMapList::iterator itr = m_MapData.begin(); itr != m_MapData.end(); ++itr)
|
||||||
|
{
|
||||||
|
cMap * Map = &(*itr);
|
||||||
|
if (a_Callback.Item(Map))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // for itr - m_MapData[]
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMap * cMapManager::GetMapData(unsigned int a_ID)
|
||||||
|
{
|
||||||
|
if (a_ID < m_MapData.size())
|
||||||
|
{
|
||||||
|
return &m_MapData[a_ID];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
|
||||||
|
if (m_MapData.size() >= 65536)
|
||||||
|
{
|
||||||
|
LOGWARN("Could not craft map - Too many maps in use");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMap Map(m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale);
|
||||||
|
|
||||||
|
m_MapData.push_back(Map);
|
||||||
|
|
||||||
|
return &m_MapData[Map.GetID()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cMapManager::GetNumMaps(void) const
|
||||||
|
{
|
||||||
|
return m_MapData.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMapManager::LoadMapData(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
|
||||||
|
cIDCountSerializer IDSerializer(m_World->GetName());
|
||||||
|
|
||||||
|
if (!IDSerializer.Load())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int MapCount = IDSerializer.GetMapCount();
|
||||||
|
|
||||||
|
m_MapData.clear();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < MapCount; ++i)
|
||||||
|
{
|
||||||
|
cMap Map(i, m_World);
|
||||||
|
|
||||||
|
cMapSerializer Serializer(m_World->GetName(), &Map);
|
||||||
|
|
||||||
|
if (!Serializer.Load())
|
||||||
|
{
|
||||||
|
LOGWARN("Could not load map #%i", Map.GetID());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_MapData.push_back(Map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMapManager::SaveMapData(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
|
||||||
|
if (m_MapData.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cIDCountSerializer IDSerializer(m_World->GetName());
|
||||||
|
|
||||||
|
IDSerializer.SetMapCount(m_MapData.size());
|
||||||
|
|
||||||
|
if (!IDSerializer.Save())
|
||||||
|
{
|
||||||
|
LOGERROR("Could not save idcounts.dat");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cMapList::iterator it = m_MapData.begin(); it != m_MapData.end(); ++it)
|
||||||
|
{
|
||||||
|
cMap & Map = *it;
|
||||||
|
|
||||||
|
cMapSerializer Serializer(m_World->GetName(), &Map);
|
||||||
|
|
||||||
|
if (!Serializer.Save())
|
||||||
|
{
|
||||||
|
LOGWARN("Could not save map #%i", Map.GetID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
78
src/MapManager.h
Normal file
78
src/MapManager.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
// MapManager.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "Map.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef cItemCallback<cMap> cMapCallback;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/** Manages the in-game maps of a single world - Thread safe. */
|
||||||
|
class cMapManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
cMapManager(cWorld * a_World);
|
||||||
|
|
||||||
|
/** Returns the map with the specified ID, NULL if out of range.
|
||||||
|
*
|
||||||
|
* WARNING: The returned map object is not thread safe.
|
||||||
|
*/
|
||||||
|
cMap * GetMapData(unsigned int a_ID);
|
||||||
|
|
||||||
|
/** Creates a new map. Returns NULL on error */
|
||||||
|
cMap * CreateMap(int a_CenterX, int a_CenterY, int a_Scale = 3);
|
||||||
|
|
||||||
|
/** Calls the callback for the map with the specified ID.
|
||||||
|
*
|
||||||
|
* Returns true if the map was found and the callback called, false if map not found.
|
||||||
|
* Callback return ignored.
|
||||||
|
*/
|
||||||
|
bool DoWithMap(int a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||||
|
|
||||||
|
/** Calls the callback for each map.
|
||||||
|
*
|
||||||
|
* Returns true if all maps processed, false if the callback aborted by returning true.
|
||||||
|
*/
|
||||||
|
bool ForEachMap(cMapCallback & a_Callback);
|
||||||
|
|
||||||
|
unsigned int GetNumMaps(void) const; // tolua_export
|
||||||
|
|
||||||
|
/** Loads the map data from the disk */
|
||||||
|
void LoadMapData(void);
|
||||||
|
|
||||||
|
/** Saves the map data to the disk */
|
||||||
|
void SaveMapData(void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::vector<cMap> cMapList;
|
||||||
|
|
||||||
|
cCriticalSection m_CS;
|
||||||
|
|
||||||
|
cMapList m_MapData;
|
||||||
|
|
||||||
|
cWorld * m_World;
|
||||||
|
|
||||||
|
}; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
|||||||
#include "../Defines.h"
|
#include "../Defines.h"
|
||||||
#include "../Endianness.h"
|
#include "../Endianness.h"
|
||||||
#include "../Scoreboard.h"
|
#include "../Scoreboard.h"
|
||||||
|
#include "../Map.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -82,6 +83,9 @@ public:
|
|||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
|
||||||
virtual void SendKeepAlive (int a_PingID) = 0;
|
virtual void SendKeepAlive (int a_PingID) = 0;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
|
||||||
|
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0;
|
||||||
|
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0;
|
||||||
|
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0;
|
||||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) = 0;
|
virtual void SendPaintingSpawn (const cPainting & a_Painting) = 0;
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
|
||||||
virtual void SendPlayerAbilities (void) = 0;
|
virtual void SendPlayerAbilities (void) = 0;
|
||||||
|
@ -97,6 +97,7 @@ enum
|
|||||||
PACKET_WINDOW_PROPERTY = 0x69,
|
PACKET_WINDOW_PROPERTY = 0x69,
|
||||||
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
|
PACKET_CREATIVE_INVENTORY_ACTION = 0x6B,
|
||||||
PACKET_UPDATE_SIGN = 0x82,
|
PACKET_UPDATE_SIGN = 0x82,
|
||||||
|
PACKET_ITEM_DATA = 0x83,
|
||||||
PACKET_PLAYER_LIST_ITEM = 0xC9,
|
PACKET_PLAYER_LIST_ITEM = 0xC9,
|
||||||
PACKET_PLAYER_ABILITIES = 0xca,
|
PACKET_PLAYER_ABILITIES = 0xca,
|
||||||
PACKET_PLUGIN_MESSAGE = 0xfa,
|
PACKET_PLUGIN_MESSAGE = 0xfa,
|
||||||
@ -614,6 +615,57 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSPacket);
|
||||||
|
|
||||||
|
WriteByte (PACKET_ITEM_DATA);
|
||||||
|
WriteShort(E_ITEM_MAP);
|
||||||
|
WriteShort(a_ID);
|
||||||
|
WriteShort(3 + a_Length);
|
||||||
|
|
||||||
|
WriteByte(0);
|
||||||
|
WriteByte(a_X);
|
||||||
|
WriteByte(a_Y);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < a_Length; ++i)
|
||||||
|
{
|
||||||
|
WriteByte(a_Colors[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSPacket);
|
||||||
|
|
||||||
|
WriteByte (PACKET_ITEM_DATA);
|
||||||
|
WriteShort(E_ITEM_MAP);
|
||||||
|
WriteShort(a_ID);
|
||||||
|
WriteShort(1 + (3 * a_Decorators.size()));
|
||||||
|
|
||||||
|
WriteByte(1);
|
||||||
|
|
||||||
|
for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it)
|
||||||
|
{
|
||||||
|
WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf));
|
||||||
|
WriteByte(it->GetPixelX());
|
||||||
|
WriteByte(it->GetPixelZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
|
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPacket);
|
cCSLock Lock(m_CSPacket);
|
||||||
|
@ -55,6 +55,9 @@ public:
|
|||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||||
virtual void SendKeepAlive (int a_PingID) override;
|
virtual void SendKeepAlive (int a_PingID) override;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||||
|
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||||
|
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||||
|
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override {} // This protocol doesn't support such message
|
||||||
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override {};
|
virtual void SendPaintingSpawn (const cPainting & a_Painting) override {};
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
|
@ -587,6 +587,61 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x34);
|
||||||
|
Pkt.WriteVarInt(a_ID);
|
||||||
|
Pkt.WriteShort (3 + a_Length);
|
||||||
|
|
||||||
|
Pkt.WriteByte(0);
|
||||||
|
Pkt.WriteByte(a_X);
|
||||||
|
Pkt.WriteByte(a_Y);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < a_Length; ++i)
|
||||||
|
{
|
||||||
|
Pkt.WriteByte(a_Colors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x34);
|
||||||
|
Pkt.WriteVarInt(a_ID);
|
||||||
|
Pkt.WriteShort (1 + (3 * a_Decorators.size()));
|
||||||
|
|
||||||
|
Pkt.WriteByte(1);
|
||||||
|
|
||||||
|
for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it)
|
||||||
|
{
|
||||||
|
Pkt.WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf));
|
||||||
|
Pkt.WriteByte(it->GetPixelX());
|
||||||
|
Pkt.WriteByte(it->GetPixelZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x34);
|
||||||
|
Pkt.WriteVarInt(a_ID);
|
||||||
|
Pkt.WriteShort (2);
|
||||||
|
|
||||||
|
Pkt.WriteByte(2);
|
||||||
|
Pkt.WriteByte(a_Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
|
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -87,6 +87,9 @@ public:
|
|||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||||
virtual void SendKeepAlive (int a_PingID) override;
|
virtual void SendKeepAlive (int a_PingID) override;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||||
|
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||||
|
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||||
|
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
virtual void SendPlayerAbilities (void) override;
|
virtual void SendPlayerAbilities (void) override;
|
||||||
|
@ -396,6 +396,36 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||||
|
{
|
||||||
|
ASSERT(m_Protocol != NULL);
|
||||||
|
m_Protocol->SendMapColumn(a_ID, a_X, a_Y, a_Colors, a_Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocolRecognizer::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
|
||||||
|
{
|
||||||
|
ASSERT(m_Protocol != NULL);
|
||||||
|
m_Protocol->SendMapDecorators(a_ID, a_Decorators);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocolRecognizer::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||||
|
{
|
||||||
|
ASSERT(m_Protocol != NULL);
|
||||||
|
m_Protocol->SendMapInfo(a_ID, a_Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
{
|
{
|
||||||
ASSERT(m_Protocol != NULL);
|
ASSERT(m_Protocol != NULL);
|
||||||
|
@ -90,6 +90,9 @@ public:
|
|||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||||
virtual void SendKeepAlive (int a_PingID) override;
|
virtual void SendKeepAlive (int a_PingID) override;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||||
|
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||||
|
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||||
|
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||||
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include "ChunkMap.h"
|
#include "ChunkMap.h"
|
||||||
#include "Generating/ChunkDesc.h"
|
#include "Generating/ChunkDesc.h"
|
||||||
#include "OSSupport/Timer.h"
|
#include "OSSupport/Timer.h"
|
||||||
|
|
||||||
|
// Serializers
|
||||||
#include "WorldStorage/ScoreboardSerializer.h"
|
#include "WorldStorage/ScoreboardSerializer.h"
|
||||||
|
|
||||||
// Entities (except mobs):
|
// Entities (except mobs):
|
||||||
@ -251,6 +253,7 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
m_bCommandBlocksEnabled(false),
|
m_bCommandBlocksEnabled(false),
|
||||||
m_bUseChatPrefixes(true),
|
m_bUseChatPrefixes(true),
|
||||||
m_Scoreboard(this),
|
m_Scoreboard(this),
|
||||||
|
m_MapManager(this),
|
||||||
m_GeneratorCallbacks(*this),
|
m_GeneratorCallbacks(*this),
|
||||||
m_TickThread(*this)
|
m_TickThread(*this)
|
||||||
{
|
{
|
||||||
@ -261,6 +264,8 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
// Load the scoreboard
|
// Load the scoreboard
|
||||||
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
||||||
Serializer.Load();
|
Serializer.Load();
|
||||||
|
|
||||||
|
m_MapManager.LoadMapData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -284,6 +289,8 @@ cWorld::~cWorld()
|
|||||||
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
|
||||||
Serializer.Save();
|
Serializer.Save();
|
||||||
|
|
||||||
|
m_MapManager.SaveMapData();
|
||||||
|
|
||||||
delete m_ChunkMap;
|
delete m_ChunkMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3025,6 +3032,7 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWorld::cTaskSaveAllChunks:
|
// cWorld::cTaskSaveAllChunks:
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "Entities/ProjectileEntity.h"
|
#include "Entities/ProjectileEntity.h"
|
||||||
#include "ForEachChunkProvider.h"
|
#include "ForEachChunkProvider.h"
|
||||||
#include "Scoreboard.h"
|
#include "Scoreboard.h"
|
||||||
|
#include "MapManager.h"
|
||||||
#include "Blocks/WorldInterface.h"
|
#include "Blocks/WorldInterface.h"
|
||||||
#include "Blocks/BroadcastInterface.h"
|
#include "Blocks/BroadcastInterface.h"
|
||||||
|
|
||||||
@ -580,9 +581,12 @@ public:
|
|||||||
/** Returns the name of the world.ini file used by this world */
|
/** Returns the name of the world.ini file used by this world */
|
||||||
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
||||||
|
|
||||||
/** Returns the associated scoreboard instance */
|
/** Returns the associated scoreboard instance. */
|
||||||
cScoreboard & GetScoreBoard(void) { return m_Scoreboard; }
|
cScoreboard & GetScoreBoard(void) { return m_Scoreboard; }
|
||||||
|
|
||||||
|
/** Returns the associated map manager instance. */
|
||||||
|
cMapManager & GetMapManager(void) { return m_MapManager; }
|
||||||
|
|
||||||
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
|
bool AreCommandBlocksEnabled(void) const { return m_bCommandBlocksEnabled; }
|
||||||
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; }
|
void SetCommandBlocksEnabled(bool a_Flag) { m_bCommandBlocksEnabled = a_Flag; }
|
||||||
|
|
||||||
@ -848,6 +852,7 @@ private:
|
|||||||
cChunkGenerator m_Generator;
|
cChunkGenerator m_Generator;
|
||||||
|
|
||||||
cScoreboard m_Scoreboard;
|
cScoreboard m_Scoreboard;
|
||||||
|
cMapManager m_MapManager;
|
||||||
|
|
||||||
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
|
/** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
|
||||||
cChunkGeneratorCallbacks m_GeneratorCallbacks;
|
cChunkGeneratorCallbacks m_GeneratorCallbacks;
|
||||||
|
276
src/WorldStorage/MapSerializer.cpp
Normal file
276
src/WorldStorage/MapSerializer.cpp
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
|
||||||
|
// MapSerializer.cpp
|
||||||
|
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "MapSerializer.h"
|
||||||
|
#include "../StringCompression.h"
|
||||||
|
#include "zlib/zlib.h"
|
||||||
|
#include "FastNBT.h"
|
||||||
|
|
||||||
|
#include "../Map.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMapSerializer::cMapSerializer(const AString& a_WorldName, cMap * a_Map)
|
||||||
|
: m_Map(a_Map)
|
||||||
|
{
|
||||||
|
AString DataPath;
|
||||||
|
Printf(DataPath, "%s/data", a_WorldName.c_str());
|
||||||
|
|
||||||
|
Printf(m_Path, "%s/map_%i.dat", DataPath.c_str(), a_Map->GetID());
|
||||||
|
|
||||||
|
cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMapSerializer::Load(void)
|
||||||
|
{
|
||||||
|
AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
|
||||||
|
if (Data.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AString Uncompressed;
|
||||||
|
int res = UncompressStringGZIP(Data.data(), Data.size(), Uncompressed);
|
||||||
|
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the NBT data:
|
||||||
|
cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
|
||||||
|
if (!NBT.IsValid())
|
||||||
|
{
|
||||||
|
// NBT Parsing failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadMapFromNBT(NBT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMapSerializer::Save(void)
|
||||||
|
{
|
||||||
|
cFastNBTWriter Writer;
|
||||||
|
|
||||||
|
SaveMapToNBT(Writer);
|
||||||
|
|
||||||
|
Writer.Finish();
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
|
||||||
|
ASSERT(TestParse.IsValid());
|
||||||
|
#endif // _DEBUG
|
||||||
|
|
||||||
|
cFile File;
|
||||||
|
if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AString Compressed;
|
||||||
|
int res = CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
|
||||||
|
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Write(Compressed.data(), Compressed.size());
|
||||||
|
File.Close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cMapSerializer::SaveMapToNBT(cFastNBTWriter & a_Writer)
|
||||||
|
{
|
||||||
|
a_Writer.BeginCompound("data");
|
||||||
|
|
||||||
|
a_Writer.AddByte("scale", m_Map->GetScale());
|
||||||
|
a_Writer.AddByte("dimension", (int) m_Map->GetDimension());
|
||||||
|
|
||||||
|
a_Writer.AddShort("width", m_Map->GetWidth());
|
||||||
|
a_Writer.AddShort("height", m_Map->GetHeight());
|
||||||
|
|
||||||
|
a_Writer.AddInt("xCenter", m_Map->GetCenterX());
|
||||||
|
a_Writer.AddInt("zCenter", m_Map->GetCenterZ());
|
||||||
|
|
||||||
|
const cMap::cColorList & Data = m_Map->GetData();
|
||||||
|
a_Writer.AddByteArray("colors", (char *) Data.data(), Data.size());
|
||||||
|
|
||||||
|
a_Writer.EndCompound();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
|
||||||
|
{
|
||||||
|
int Data = a_NBT.FindChildByName(0, "data");
|
||||||
|
if (Data < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrLine = a_NBT.FindChildByName(Data, "scale");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
unsigned int Scale = a_NBT.GetByte(CurrLine);
|
||||||
|
m_Map->SetScale(Scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "dimension");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
|
||||||
|
|
||||||
|
ASSERT(Dimension == m_Map->m_World->GetDimension());
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "width");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
unsigned int Width = a_NBT.GetShort(CurrLine);
|
||||||
|
m_Map->m_Width = Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "height");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
unsigned int Height = a_NBT.GetShort(CurrLine);
|
||||||
|
m_Map->m_Height = Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "xCenter");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
int CenterX = a_NBT.GetInt(CurrLine);
|
||||||
|
m_Map->m_CenterX = CenterX;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "zCenter");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
int CenterZ = a_NBT.GetInt(CurrLine);
|
||||||
|
m_Map->m_CenterZ = CenterZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NumPixels = m_Map->GetNumPixels();
|
||||||
|
m_Map->m_Data.resize(NumPixels);
|
||||||
|
|
||||||
|
CurrLine = a_NBT.FindChildByName(Data, "colors");
|
||||||
|
if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray))
|
||||||
|
{
|
||||||
|
memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cIDCountSerializer::cIDCountSerializer(const AString & a_WorldName) : m_MapCount(0)
|
||||||
|
{
|
||||||
|
AString DataPath;
|
||||||
|
Printf(DataPath, "%s/data", a_WorldName.c_str());
|
||||||
|
|
||||||
|
Printf(m_Path, "%s/idcounts.dat", DataPath.c_str());
|
||||||
|
|
||||||
|
cFile::CreateFolder(FILE_IO_PREFIX + DataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cIDCountSerializer::Load(void)
|
||||||
|
{
|
||||||
|
AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
|
||||||
|
if (Data.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: idcounts.dat is not compressed (raw format)
|
||||||
|
|
||||||
|
// Parse the NBT data:
|
||||||
|
cParsedNBT NBT(Data.data(), Data.size());
|
||||||
|
if (!NBT.IsValid())
|
||||||
|
{
|
||||||
|
// NBT Parsing failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrLine = NBT.FindChildByName(0, "map");
|
||||||
|
if (CurrLine >= 0)
|
||||||
|
{
|
||||||
|
m_MapCount = (int)NBT.GetShort(CurrLine) + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_MapCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cIDCountSerializer::Save(void)
|
||||||
|
{
|
||||||
|
cFastNBTWriter Writer;
|
||||||
|
|
||||||
|
if (m_MapCount > 0)
|
||||||
|
{
|
||||||
|
Writer.AddShort("map", m_MapCount - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Finish();
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
|
||||||
|
ASSERT(TestParse.IsValid());
|
||||||
|
#endif // _DEBUG
|
||||||
|
|
||||||
|
cFile File;
|
||||||
|
if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: idcounts.dat is not compressed (raw format)
|
||||||
|
|
||||||
|
File.Write(Writer.GetResult().data(), Writer.GetResult().size());
|
||||||
|
File.Close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
86
src/WorldStorage/MapSerializer.h
Normal file
86
src/WorldStorage/MapSerializer.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
// MapSerializer.h
|
||||||
|
|
||||||
|
// Declares the cMapSerializer class that is used for saving maps into NBT format used by Anvil
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
|
class cFastNBTWriter;
|
||||||
|
class cParsedNBT;
|
||||||
|
class cMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Utility class used to serialize maps. */
|
||||||
|
class cMapSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cMapSerializer(const AString& a_WorldName, cMap * a_Map);
|
||||||
|
|
||||||
|
/** Try to load the scoreboard */
|
||||||
|
bool Load(void);
|
||||||
|
|
||||||
|
/** Try to save the scoreboard */
|
||||||
|
bool Save(void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SaveMapToNBT(cFastNBTWriter & a_Writer);
|
||||||
|
|
||||||
|
bool LoadMapFromNBT(const cParsedNBT & a_NBT);
|
||||||
|
|
||||||
|
cMap * m_Map;
|
||||||
|
|
||||||
|
AString m_Path;
|
||||||
|
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Utility class used to serialize item ID counts.
|
||||||
|
*
|
||||||
|
* In order to perform bounds checking (while loading),
|
||||||
|
* the last registered ID of each item is serialized to an NBT file.
|
||||||
|
*/
|
||||||
|
class cIDCountSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cIDCountSerializer(const AString & a_WorldName);
|
||||||
|
|
||||||
|
/** Try to load the ID counts */
|
||||||
|
bool Load(void);
|
||||||
|
|
||||||
|
/** Try to save the ID counts */
|
||||||
|
bool Save(void);
|
||||||
|
|
||||||
|
inline unsigned int GetMapCount(void) const { return m_MapCount; }
|
||||||
|
|
||||||
|
inline void SetMapCount(unsigned int a_MapCount) { m_MapCount = a_MapCount; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
AString m_Path;
|
||||||
|
|
||||||
|
unsigned int m_MapCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user