diff --git a/MissionEditor/Helpers.h b/MissionEditor/Helpers.h index 7baf5a6..729bbae 100644 --- a/MissionEditor/Helpers.h +++ b/MissionEditor/Helpers.h @@ -134,4 +134,15 @@ inline CString WaypointToString(int num) ret += firstChar; ret += secondChar; return ret; +} + +inline void GetNodeID(CString& name, int n) +{ + name.Format("%03d", n); +} +inline CString GetNodeID(int n) +{ + CString ret; + GetNodeID(ret, n); + return ret; } \ No newline at end of file diff --git a/MissionEditor/IsoView.cpp b/MissionEditor/IsoView.cpp index 2c5a4a7..1340111 100644 --- a/MissionEditor/IsoView.cpp +++ b/MissionEditor/IsoView.cpp @@ -61,7 +61,6 @@ static char THIS_FILE[] = __FILE__; /* Externals */ extern ACTIONDATA AD; -void GetNodeName(CString& name, int n); /* --------- */ /* Overlay picture table (maximum overlay count=0xFF) */ diff --git a/MissionEditor/MapData.cpp b/MissionEditor/MapData.cpp index c77d2d6..dda9100 100644 --- a/MissionEditor/MapData.cpp +++ b/MissionEditor/MapData.cpp @@ -33,6 +33,7 @@ #include "Structs.h" #include "Tube.h" #include "IniMega.h" +#include "Helpers.h" #ifdef _DEBUG #undef THIS_FILE @@ -50,10 +51,6 @@ void DoEvents() }*/ } - -void GetNodeName(CString& name, int n); - - CString GetFree(const char* sectionName) { auto const ini = Map->GetIniFile(); @@ -1768,7 +1765,7 @@ void CMapData::UpdateNodes(BOOL bSave) int nodeCount = sec.GetInteger("NodeCount"); for (auto idx = 0; idx < nodeCount; idx++) { CString nodeName; - GetNodeName(nodeName, idx); + GetNodeID(nodeName, idx); auto const& nodeVal = sec.GetString(nodeName); CString type, sx, sy; type = GetParam(nodeVal, 0); @@ -2034,26 +2031,9 @@ void CMapData::DeleteTerrain(DWORD dwIndex) } -void CMapData::DeleteNode(LPCTSTR lpHouse, DWORD dwIndex) +void CMapData::DeleteNode(const CString& house, const int dwIndex) { - CString nodeName; // p is last node - auto const nodeCount = m_mapfile.GetInteger(lpHouse, "NodeCount"); - GetNodeName(nodeName, nodeCount - 1); - - for (auto i = dwIndex; i < nodeCount - 1; i++) { - CString prevNodeName, nextNodeName; - GetNodeName(prevNodeName, i); - GetNodeName(nextNodeName, i + 1); - m_mapfile.SetString(lpHouse, prevNodeName, m_mapfile.GetString(lpHouse, nextNodeName)); - } - - auto const& pSec = m_mapfile.TryGetSection(lpHouse); - pSec->RemoveAt(dwIndex); - - char nodeCountStr[50]; - itoa(nodeCount - 1, nodeCountStr, 10); - m_mapfile.SetString(lpHouse, "NodeCount", nodeCountStr); - + DeleteBuildingNodeFrom(house, dwIndex, m_mapfile); UpdateNodes(FALSE); } @@ -2168,7 +2148,7 @@ BOOL CMapData::AddNode(NODE* lpNode, WORD dwPos) nodeCount--; CString p; - GetNodeName(p, nodeCount); + GetNodeID(p, nodeCount); auto&& nodeRecord = node.type + "," + node.y + "," + node.x; diff --git a/MissionEditor/MapData.h b/MissionEditor/MapData.h index b4c2675..fec8422 100644 --- a/MissionEditor/MapData.h +++ b/MissionEditor/MapData.h @@ -264,7 +264,7 @@ public: CString GetStructureData(DWORD dwIndex, STRUCTURE* lpStructure) const; BOOL AddWaypoint(CString lpID, DWORD dwPos); - void DeleteNode(LPCTSTR lpHouse, DWORD dwIndex); + void DeleteNode(const CString& house, const int index); void DeleteTerrain(DWORD dwIndex); void DeleteAircraft(DWORD dwIndex); void DeleteStructure(DWORD dwIndex); diff --git a/MissionEditor/functions.cpp b/MissionEditor/functions.cpp index 231952f..42071ff 100644 --- a/MissionEditor/functions.cpp +++ b/MissionEditor/functions.cpp @@ -1320,27 +1320,7 @@ CString GetFreeID() return ""; } -void GetNodeName(CString& name, int n) -{ - char c[5]; - char p[6]; - memset(p, 0, 6); - _itoa_s(n, c, 10); - strcpy_s(p, c); - - if (strlen(c) == 1) { - memcpy(c, "00", 2); - strcpy_s(c + 2, sizeof(c) - 2, p); - } else if (strlen(c) == 2) { - memcpy(c, "0", 1); - strcpy_s(c + 1, sizeof(c) - 1, p); - } else if (strlen(c) == 3) { - strcpy_s(c, p); - } - - name = c; -} - +// UNUSED int GetNodeAt(CString& owner, CString& buildingTypeID, int x, int y) { CIniFile& ini = Map->GetIniFile(); @@ -1362,7 +1342,7 @@ int GetNodeAt(CString& owner, CString& buildingTypeID, int x, int y) for (auto i = 0; i < nodeCount; i++) { CString nodeName; - GetNodeName(nodeName, i); + GetNodeID(nodeName, i); CString sx, sy; buildingTypeID = GetParam(ownerSection.GetString(nodeName), 0); diff --git a/MissionEditor/functions.h b/MissionEditor/functions.h index 0402147..8328883 100644 --- a/MissionEditor/functions.h +++ b/MissionEditor/functions.h @@ -26,6 +26,8 @@ #include #include "Helpers.h" +class CIniFile; +class CSliderCtrl; using std::string; bool deleteFile(const std::string& u8FilePath); @@ -56,9 +58,28 @@ std::string utf16ToUtf8(const std::wstring& utf16); std::string utf16ToACP(const std::wstring& utf16); // map functions -int GetNodeAt(string& owner, string& type, int x, int y); -int SetNodeAt(string owner, string type, int x, int y); -void ClearNode(int n, string owner); +inline void DeleteBuildingNodeFrom(const CString& house, const int index, CIniFile& ini) +{ + auto const nodeCount = ini.GetInteger(house, "NodeCount"); + ASSERT(nodeCount > 0); + // override value from current ID + CString prevNodeName, nextNodeName, lastData; + for (auto i = index; i < nodeCount - 1; i++) { + GetNodeID(prevNodeName, i); + GetNodeID(nextNodeName, i + 1); + lastData = ini.GetString(house, nextNodeName); + ini.SetString(house, prevNodeName, lastData); + } + auto const& pSec = ini.TryGetSection(house); + ASSERT(pSec != nullptr); + if (pSec) { + // always remove the last one + auto const result = pSec->RemoveByKey(GetNodeID(nodeCount - 1)); + ASSERT(result == true); + } + ini.SetInteger(house, "NodeCount", nodeCount - 1); +} + CString GetFreeID(); diff --git a/UnitTest/CIni_Test.cpp b/UnitTest/CIni_Test.cpp index e3ff204..e2e3b7d 100644 --- a/UnitTest/CIni_Test.cpp +++ b/UnitTest/CIni_Test.cpp @@ -1,31 +1,7 @@ -#include "stdafx.h" +#include "StdAfx.h" +#include "CIni_Test.h" #include "../MissionEditor/IniFile.h" -class IniTestHelper -{ - std::string m_fileName; - - void writeDownContent(const char* pContent) { - std::ofstream iniFile(m_fileName.c_str()); - ASSERT(iniFile.is_open() == true); - iniFile << pContent; - iniFile.flush(); - iniFile.close(); - } - -public: - IniTestHelper(std::string&& name, const char* pContent) : - m_fileName(std::move(name)) - { - ASSERT(!m_fileName.empty()); - ASSERT(pContent != nullptr); - writeDownContent(pContent); - } - ~IniTestHelper() { - remove(m_fileName.c_str()); - } - -}; TEST(CIniFileClass, LoadFileTest) { auto const fileName = "test.ini"; diff --git a/UnitTest/CIni_Test.h b/UnitTest/CIni_Test.h new file mode 100644 index 0000000..b942db2 --- /dev/null +++ b/UnitTest/CIni_Test.h @@ -0,0 +1,28 @@ +#pragma once +#include "StdAfx.h" + +class IniTestHelper +{ + std::string m_fileName; + + void writeDownContent(const char* pContent) { + std::ofstream iniFile(m_fileName.c_str()); + ASSERT(iniFile.is_open() == true); + iniFile << pContent; + iniFile.flush(); + iniFile.close(); + } + +public: + IniTestHelper(std::string&& name, const char* pContent) : + m_fileName(std::move(name)) + { + ASSERT(!m_fileName.empty()); + ASSERT(pContent != nullptr); + writeDownContent(pContent); + } + ~IniTestHelper() { + remove(m_fileName.c_str()); + } + +}; \ No newline at end of file diff --git a/UnitTest/Serde_Test.cpp b/UnitTest/Serde_Test.cpp index c535991..28576c4 100644 --- a/UnitTest/Serde_Test.cpp +++ b/UnitTest/Serde_Test.cpp @@ -1,6 +1,9 @@ -#include "stdafx.h" +#include "StdAfx.h" #include "MissionEditorPackLib.h" +#include "IniFile.h" +#include "functions.h" +#include "CIni_Test.h" using std::cout; using std::endl; @@ -109,4 +112,75 @@ TEST(SerdeTest, OverlayDataPackSerde) ASSERT_EQ(b64Input.size(), strlen(reinterpret_cast(encoded.get()))); ASSERT_TRUE(0 == memcmp(encoded.get(), b64Input.data(), b64Input.size())); +} + +TEST(SerdeTest, HouseBuildingNodeTest) +{ + ASSERT_EQ("000", GetNodeID(0)); + ASSERT_EQ("005", GetNodeID(5)); + ASSERT_EQ("010", GetNodeID(10)); + ASSERT_EQ("123", GetNodeID(123)); +} +TEST(SerdeTest, HouseBuildingNodeDeleteTest) +{ + auto const fileName = "test.ini"; + IniTestHelper helper(fileName, R"( +[Russian1 House] +IQ=5 +000=NALASR,86,63 +001=NALASR,89,64 +002=NALASR,83,64 +003=NARADR,71,48 +004=NAREFN,69,66 +005=NALASR,78,42 +006=NALASR,73,42 +007=NAFLAK,61,34 +008=NAFLAK,61,32 +009=NAFLAK,62,41 +010=TESLA,61,41 +011=NAFLAK,61,40 +012=NAPOWR,91,23 +013=NAFLAK,64,63 +014=NAFLAK,91,63 +015=NAPOWR,62,39 +016=TESLA,71,41 +017=NAHAND,76,57 +018=NAPOWR,65,37 +019=NALASR,83,50 +020=NAWEAP,63,59 +021=NAWEAP,63,54 +022=NALASR,77,24 +023=NAFLAK,81,63 +024=NALASR,79,24 +025=TESLA,81,24 +Edge=North +Color=DarkRed +Allies=C2 House,Russian1 House,Russian2 House,CivilianArmy House,Civilian1 House,Other1 House,Civilian2 House +Country=Russian1 +Credits=600 +NodeCount=26 +TechLevel=5 +PercentBuilt=100 +PlayerControl=no + +)"); + + CString houseName = "Russian1 House"; + CIniFile file; + ASSERT_EQ(file.LoadFile(std::string(fileName)), 0); + + // remove last + DeleteBuildingNodeFrom(houseName, 25, file); + ASSERT_EQ(file.GetInteger(houseName, "NodeCount"), 25); + + // remove middle + DeleteBuildingNodeFrom(houseName, 23, file); + ASSERT_EQ(file.GetInteger(houseName, "NodeCount"), 24); + ASSERT_EQ(file.GetString(houseName, GetNodeID(23)), "NALASR,79,24"); + + // remove first + DeleteBuildingNodeFrom(houseName, 0, file); + ASSERT_EQ(file.GetInteger(houseName, "NodeCount"), 23); + ASSERT_EQ(file.GetString(houseName, GetNodeID(0)), "NALASR,89,64"); + ASSERT_EQ(file.GetString(houseName, GetNodeID(22)), "NALASR,79,24"); } \ No newline at end of file diff --git a/UnitTest/StdAfx.h b/UnitTest/StdAfx.h index fe450d1..ba28fec 100644 --- a/UnitTest/StdAfx.h +++ b/UnitTest/StdAfx.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include using std::cout; using std::endl; diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index d72ae3d..e0e2ac3 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -148,6 +148,7 @@ + diff --git a/UnitTest/UnitTest.vcxproj.filters b/UnitTest/UnitTest.vcxproj.filters index 534a111..c17a41f 100644 --- a/UnitTest/UnitTest.vcxproj.filters +++ b/UnitTest/UnitTest.vcxproj.filters @@ -47,5 +47,8 @@ 头文件 + + 头文件 + \ No newline at end of file