1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "map.h"
4
5#include <base/log.h>
6
7#include <engine/storage.h>
8
9#include <game/mapitems.h>
10
11CMap::CMap() = default;
12
13int CMap::GetDataSize(int Index) const
14{
15 return m_DataFile.GetDataSize(Index);
16}
17
18void *CMap::GetData(int Index)
19{
20 return m_DataFile.GetData(Index);
21}
22
23void *CMap::GetDataSwapped(int Index)
24{
25 return m_DataFile.GetDataSwapped(Index);
26}
27
28const char *CMap::GetDataString(int Index)
29{
30 return m_DataFile.GetDataString(Index);
31}
32
33void CMap::UnloadData(int Index)
34{
35 m_DataFile.UnloadData(Index);
36}
37
38int CMap::NumData() const
39{
40 return m_DataFile.NumData();
41}
42
43int CMap::GetItemSize(int Index)
44{
45 return m_DataFile.GetItemSize(Index);
46}
47
48void *CMap::GetItem(int Index, int *pType, int *pId)
49{
50 return m_DataFile.GetItem(Index, pType, pId);
51}
52
53void CMap::GetType(int Type, int *pStart, int *pNum)
54{
55 m_DataFile.GetType(Type, pStart, pNum);
56}
57
58int CMap::FindItemIndex(int Type, int Id)
59{
60 return m_DataFile.FindItemIndex(Type, Id);
61}
62
63void *CMap::FindItem(int Type, int Id)
64{
65 return m_DataFile.FindItem(Type, Id);
66}
67
68int CMap::NumItems() const
69{
70 return m_DataFile.NumItems();
71}
72
73bool CMap::Load(const char *pMapName)
74{
75 IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
76 if(!pStorage)
77 return false;
78
79 // Ensure current datafile is not left in an inconsistent state if loading fails,
80 // by loading the new datafile separately first.
81 CDataFileReader NewDataFile;
82 if(!NewDataFile.Open(pStorage, pFilename: pMapName, StorageType: IStorage::TYPE_ALL))
83 return false;
84
85 // Check version
86 const CMapItemVersion *pItem = (CMapItemVersion *)NewDataFile.FindItem(Type: MAPITEMTYPE_VERSION, Id: 0);
87 if(pItem == nullptr || pItem->m_Version != CMapItemVersion::CURRENT_VERSION)
88 {
89 log_error("map/load", "Error: map version not supported.");
90 NewDataFile.Close();
91 return false;
92 }
93
94 // Replace compressed tile layers with uncompressed ones
95 int GroupsStart, GroupsNum, LayersStart, LayersNum;
96 NewDataFile.GetType(Type: MAPITEMTYPE_GROUP, pStart: &GroupsStart, pNum: &GroupsNum);
97 NewDataFile.GetType(Type: MAPITEMTYPE_LAYER, pStart: &LayersStart, pNum: &LayersNum);
98 for(int g = 0; g < GroupsNum; g++)
99 {
100 const CMapItemGroup *pGroup = static_cast<CMapItemGroup *>(NewDataFile.GetItem(Index: GroupsStart + g));
101 for(int l = 0; l < pGroup->m_NumLayers; l++)
102 {
103 CMapItemLayer *pLayer = static_cast<CMapItemLayer *>(NewDataFile.GetItem(Index: LayersStart + pGroup->m_StartLayer + l));
104 if(pLayer->m_Type == LAYERTYPE_TILES)
105 {
106 CMapItemLayerTilemap *pTilemap = reinterpret_cast<CMapItemLayerTilemap *>(pLayer);
107 if(pTilemap->m_Version >= CMapItemLayerTilemap::TILE_SKIP_MIN_VERSION)
108 {
109 const size_t TilemapSize = (size_t)pTilemap->m_Width * pTilemap->m_Height * sizeof(CTile);
110 CTile *pTiles = static_cast<CTile *>(malloc(size: TilemapSize));
111 ExtractTiles(pDest: pTiles, DestSize: (size_t)pTilemap->m_Width * pTilemap->m_Height, pSrc: static_cast<CTile *>(NewDataFile.GetData(Index: pTilemap->m_Data)), SrcSize: NewDataFile.GetDataSize(Index: pTilemap->m_Data) / sizeof(CTile));
112 NewDataFile.ReplaceData(Index: pTilemap->m_Data, pData: reinterpret_cast<char *>(pTiles), Size: TilemapSize);
113 }
114 }
115 }
116 }
117
118 // Replace existing datafile with new datafile
119 m_DataFile.Close();
120 m_DataFile = std::move(NewDataFile);
121 return true;
122}
123
124void CMap::Unload()
125{
126 m_DataFile.Close();
127}
128
129bool CMap::IsLoaded() const
130{
131 return m_DataFile.IsOpen();
132}
133
134IOHANDLE CMap::File() const
135{
136 return m_DataFile.File();
137}
138
139SHA256_DIGEST CMap::Sha256() const
140{
141 return m_DataFile.Sha256();
142}
143
144unsigned CMap::Crc() const
145{
146 return m_DataFile.Crc();
147}
148
149int CMap::MapSize() const
150{
151 return m_DataFile.MapSize();
152}
153
154void CMap::ExtractTiles(CTile *pDest, size_t DestSize, const CTile *pSrc, size_t SrcSize)
155{
156 size_t DestIndex = 0;
157 size_t SrcIndex = 0;
158 while(DestIndex < DestSize && SrcIndex < SrcSize)
159 {
160 for(unsigned Counter = 0; Counter <= pSrc[SrcIndex].m_Skip && DestIndex < DestSize; Counter++)
161 {
162 pDest[DestIndex] = pSrc[SrcIndex];
163 pDest[DestIndex].m_Skip = 0;
164 DestIndex++;
165 }
166 SrcIndex++;
167 }
168}
169
170extern IEngineMap *CreateEngineMap() { return new CMap; }
171