Merge pull request #6 from revengenowstudio/feature/tree-view

Feature/tree view
This commit is contained in:
Zero Fanker 2024-04-30 23:01:21 -04:00 committed by GitHub
commit 3c3464801b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 919 additions and 529 deletions

View file

@ -163,7 +163,7 @@ void CBasic::OnChangeName()
void CBasic::UpdateData()
{
// MessageBox("This function ( UpdateData() ) should not be called here... please report to the author.");
errstream << "CBasic::UpdateData() called - should not be called" << endl;
errstream << "CBasic::UpdateData() called - should not be called" << std::endl;
errstream.flush();
}

View file

@ -32,7 +32,7 @@
#include <vector>
using namespace std;
using std::vector;
#define COMBOUINPUT_HOUSES 0
#define COMBOUINPUT_COUNTRIES 1

View file

@ -112,7 +112,7 @@ CFinalSunApp::CFinalSunApp()
log += "finalalert2log.txt";
#endif
m_u8LogFileName = log;
errstream.open(m_u8LogFileName, ios_base::trunc);
errstream.open(m_u8LogFileName, std::ios_base::trunc);
errstream << "\uFEFF"; // BOM
#ifdef TS_MODE

View file

@ -69,6 +69,8 @@ static char THIS_FILE[] = __FILE__;
#include <io.h>
#include <stdio.h>
using std::endl;
extern ACTIONDATA AD;
extern BOOL bNoDraw;

39
MissionEditor/INIMeta.cpp Normal file
View file

@ -0,0 +1,39 @@
#include "StdAfx.h"
#include "INIMeta.h"
#include <set>
void IniFileGroup::Append(const CIniFile& INI)
{
m_group.push_back(&INI);
}
const CIniFile* IniFileGroup::Nth(int idx) const
{
return m_group.at(idx);
}
const CString& IniFileGroup::GetString(const CString & section, const CString & key) const
{
for (auto it = m_group.rbegin(); it != m_group.rend(); ++it) {
auto const& got = (*it)->GetString(section, key);
if (!got.IsEmpty()) {
return got;
}
}
return CIniFileSection::EmptyValue;
}
CString IniFileGroup::GetStringOr(const CString & section, const CString & key, const CString& def) const
{
auto const& got = this->GetString(section, key);
if (!got.IsEmpty()) {
return got;
}
return def;
}
IniSectionGroup IniFileGroup::GetSection(const CString& section) const
{
return IniSectionGroup(*this, section);
}

142
MissionEditor/INIMeta.h Normal file
View file

@ -0,0 +1,142 @@
#pragma once
#include <afx.h>
#include "IniFile.h"
#include <vector>
#include <map>
using IndiceStorage = std::vector<CString>;
using SequencedSection = std::vector<CString>;
class IniSectionGroup;
/*
* @brief This class uses to simulation a combination of a few ini dictionaries, to
act as they are inside a same ini
*/
class IniFileGroup
{
friend class IniMegaFile;
public:
using StorageType = std::vector<const CIniFile*>;
IniFileGroup() = default;
const CString& GetString(const CString& section, const CString& key) const;
CString GetStringOr(const CString& section, const CString& key, const CString& def) const;
IniSectionGroup GetSection(const CString& section) const;
auto Size() const { return m_group.size(); }
void Append(const CIniFile& INI);
const CIniFile* Nth(int idx) const;
auto begin() const { return m_group.begin(); }
auto end() const { return m_group.end(); }
bool empty() const { return m_group.empty(); }
private:
StorageType m_group;
};
class IniSectionGroup
{
using KvIter = CIniFileSection::Container::const_iterator;
using GroupIter = IniFileGroup::StorageType::const_iterator;
public:
class Iterator;
friend class Iterator;
class Iterator {
public:
Iterator(const CString& section,
GroupIter groupIter,
GroupIter groupIterEnd,
KvIter kvIter,
KvIter kvIterEnd
) :
m_section(section),
m_groupIter(groupIter),
m_groupIterEnd(groupIterEnd),
m_kvIter(kvIter),
m_kvIterEnd(kvIterEnd)
{
}
Iterator& operator++() {
// section content still working
if (m_kvIter != std::prev(m_kvIterEnd)) {
m_kvIter++;
return *this;
}
m_groupIter++;
if (m_groupIter != m_groupIterEnd) {
auto [beg, end] = IniSectionGroup::acquireNextKvGroup(m_section, m_groupIter, m_groupIterEnd);
m_kvIter = beg;
m_kvIterEnd = end;
} else {
m_kvIter = m_kvIterEnd;// to make (==) works
}
return *this;
}
auto const& operator*() const {
return *m_kvIter;
}
bool operator==(const Iterator& rhs) const {
return m_groupIter == rhs.m_groupIter;
}
private:
GroupIter m_groupIter;
GroupIter m_groupIterEnd;
KvIter m_kvIter;
KvIter m_kvIterEnd;
const CString& m_section;
};
IniSectionGroup(const IniFileGroup& source, const CString& secName) :
m_source(source),
m_section(secName)
{
}
Iterator begin() const {
auto groupBeg = m_source.begin();
auto [secItBeg, secItEnd] = acquireNextKvGroup(groupBeg);
return Iterator(m_section, groupBeg, m_source.end(), secItBeg, secItEnd);
}
Iterator end() const {
auto secItEnd = KvIter{};
if (!m_source.empty()) {
auto const& sec = (*std::prev(m_source.end()))->GetSection(m_section);
secItEnd = sec.end();
}
return Iterator(m_section, m_source.end(), m_source.end(), secItEnd, secItEnd);
}
private:
// attention: beginning iter
static std::pair< KvIter, KvIter> acquireNextKvGroup(const CString& section, GroupIter& beg, const GroupIter end) {
auto secItBeg = KvIter{};
auto secItEnd = KvIter{};
for (; beg != end; ++beg) {
auto const& sec = (*beg)->GetSection(section);
if (sec.Size() == 0) {
continue;
}
secItBeg = sec.begin();
secItEnd = sec.end();
break;
}
return { secItBeg, secItEnd };
}
std::pair< KvIter, KvIter> acquireNextKvGroup(GroupIter& beg) const {
return acquireNextKvGroup(m_section, beg, m_source.end());
}
const IniFileGroup& m_source;
CString m_section;
};

View file

@ -38,12 +38,14 @@
#include <ios>
#include "IniHelper.h"
using namespace std;
using std::vector;
using std::map;
class CIniFileSection
{
static const CString EmptyValue;
public:
using Container = vector<std::pair<CString, CString>>;
static const CString EmptyValue;
CIniFileSection();
virtual ~CIniFileSection();
@ -197,7 +199,7 @@ public:
private:
map<CString, int64_t> value_pos{};
vector<std::pair<CString, CString>> value_pairs{};// sequenced
Container value_pairs{};// sequenced
};
class CIniFile

View file

@ -358,8 +358,8 @@ __forceinline void BlitTerrain(void* dst, int x, int y, int dleft, int dtop, int
short& left = st.vborder[e].left;
short& right = st.vborder[e].right;
auto l = max(left, srcRect.left);
auto r = min(right, static_cast<short>(srcRect.right - 1));
auto l = std::max(left, srcRect.left);
auto r = std::min(right, static_cast<short>(srcRect.right - 1));
for (i = l; i <= r; i++) {
//if (i < srcRect.left || i >= srcRect.right)
{
@ -640,7 +640,7 @@ __forceinline void BlitPic(void* dst, int x, int y, int dleft, int dtop, int dpi
int l = pLighting[spos];
BYTE* bc = reinterpret_cast<BYTE*>(&c);
for (int i = 0; i < 4; ++i)
bc[i] = min(255, bc[i] * (200 + l * 300 / 255) / 255); // game seems to overbrighten and have a lot of ambient - if you change this, also change Loading.cpp shp lighting value so that shp light stays at 1.0
bc[i] = std::min(255, bc[i] * (200 + l * 300 / 255) / 255); // game seems to overbrighten and have a lot of ambient - if you change this, also change Loading.cpp shp lighting value so that shp light stays at 1.0
//bc[i] = min(255, bc[i] * (0 + l * (255 - 0) / 255) / 255);
}
memcpy(dest, &c, bpp);
@ -3674,7 +3674,7 @@ void CIsoView::DrawTube(const CTube& tube, const DDSURFACEDESC2* lockedDDSD, con
const auto col = color ? m_color_converter->GetColor(*color) : (type0 ? m_color_converter->GetColor(255, 0, 0) : m_color_converter->GetColor(0, 0, 255));
ProjectedVec lineOffset = type0 ? ProjectedVec() : ProjectedVec(1, 1);
int lowestHeight = min(Map->GetHeightAt(tube.getStartCoords()), Map->GetHeightAt(tube.getEndCoords()));
int lowestHeight = std::min(Map->GetHeightAt(tube.getStartCoords()), Map->GetHeightAt(tube.getEndCoords()));
LineDrawer ld(lockedDDSD->lpSurface, bpp, lockedDDSD->dwWidth, lockedDDSD->dwHeight, lockedDDSD->lPitch);
auto startDraw = GetRenderTargetCoordinates(tube.getStartCoords(), lowestHeight);
ld.MoveTo(startDraw.x + f_x / 2 + lineOffset.x, startDraw.y + f_y / 2 + lineOffset.y);
@ -4681,7 +4681,7 @@ void CIsoView::OnTimer(UINT_PTR nIDEvent)
InvalidateRect(NULL, FALSE);
} else {
errstream << "Timer calls InitTMPs()" << endl;
errstream << "Timer calls InitTMPs()" << std::endl;
errstream.flush();
theApp.m_loading->InitTMPs();
@ -5062,10 +5062,10 @@ void CIsoView::DrawMap()
auto topRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true);
auto bottomLeft = GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true);
auto bottomRight = GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true);
left = min(topLeft.x, topRight.x);
top = min(topLeft.y, topRight.y);
right = max(bottomLeft.x, bottomRight.x);
bottom = max(bottomLeft.y, bottomRight.y);
left = std::min(topLeft.x, topRight.x);
top = std::min(topLeft.y, topRight.y);
right = std::max(bottomLeft.x, bottomRight.x);
bottom = std::max(bottomLeft.y, bottomRight.y);
}
// some large buildings may be out of reach:
@ -6029,7 +6029,7 @@ void CIsoView::OnKillFocus(CWnd* pNewWnd)
CView::OnKillFocus(pNewWnd);
if (rscroll) {
errstream << "Killing scroll" << endl;
errstream << "Killing scroll" << std::endl;
errstream.flush();
ReleaseCapture();

View file

@ -4562,7 +4562,7 @@ void CLoading::LoadStrings()
BYTE* lpData = NULL;
DWORD dwSize;
if (DoesFileExist((std::string(TSPath) + "\\" + file).c_str())) {
std::ifstream f(std::string(TSPath) + "\\" + file, ios::binary);
std::ifstream f(std::string(TSPath) + "\\" + file, std::ios::binary);
if (f.good()) {
f.seekg(0, std::ios::end);
auto size = f.tellg();
@ -4582,7 +4582,7 @@ void CLoading::LoadStrings()
//HMIXFILE hMix=m_hLanguage;
if (hMix) {
if (FSunPackLib::XCC_ExtractFile(file, u8AppDataPath + "\\RA2Tmp.csf", hMix)) {
std::ifstream f(u8AppDataPath + "\\RA2Tmp.csf", ios::binary);
std::ifstream f(u8AppDataPath + "\\RA2Tmp.csf", std::ios::binary);
if (f.good()) {
f.seekg(0, std::ios::end);
auto size = f.tellg();

View file

@ -34,7 +34,7 @@
extern TILEDATA** tiledata;
extern DWORD* tiledata_count;
extern ofstream errstream;
extern std::ofstream errstream;
extern map<int, int> tilesets_start;
extern CIniFile* tiles;
extern CFinalSunApp theApp;

View file

@ -97,10 +97,10 @@ void CMiniMap::OnDraw(CDC* pDC)
auto topRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, 0), false, true));
auto bottomLeft = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(0, cr.bottom), false, true));
auto bottomRight = Map->GetMiniMapPos(isoview.GetMapCoordinatesFromClientCoordinates(CPoint(cr.right, cr.bottom), false, true));
auto left = min(topLeft.x, topRight.x);
auto top = min(topLeft.y, topRight.y);
auto right = max(bottomLeft.x, bottomRight.x);
auto bottom = max(bottomLeft.y, bottomRight.y);
auto left = std::min(topLeft.x, topRight.x);
auto top = std::min(topLeft.y, topRight.y);
auto right = std::max(bottomLeft.x, bottomRight.x);
auto bottom = std::max(bottomLeft.y, bottomRight.y);
CPoint center(r.right / 2, r.bottom / 2);
selRect.left = left * m_scale;

View file

@ -347,7 +347,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FinalAlertDebug YR|x64'">
<ClCompile>
<PreprocessorDefinitions>RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\MissionEditorPackLib</AdditionalIncludeDirectories>
</ClCompile>
<ResourceCompile>
@ -419,7 +419,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FinalAlertRelease YR|x64'">
<ClCompile>
<PreprocessorDefinitions>RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NOMINMAX;RA2_MODE;YR_MODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\MissionEditorPackLib</AdditionalIncludeDirectories>
</ClCompile>
<ResourceCompile>
@ -498,6 +498,7 @@
<ClCompile Include="Infantry.cpp" />
<ClCompile Include="Info.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="INIMeta.cpp" />
<ClCompile Include="InputBox.cpp" />
<ClCompile Include="IsoView.cpp" />
<ClCompile Include="Lighting.cpp" />
@ -609,6 +610,7 @@
<ClInclude Include="ComboUInputDlg.h" />
<ClInclude Include="defines.h" />
<ClInclude Include="IniHelper.h" />
<ClInclude Include="INIMeta.h" />
<ClInclude Include="LineDrawer.h" />
<ClInclude Include="DynamicGraphDlg.h" />
<ClInclude Include="FinalSun.h" />
@ -660,6 +662,7 @@
<ClInclude Include="SingleplayerSettings.h" />
<ClInclude Include="SpecialFlags.h" />
<ClInclude Include="StdAfx.h" />
<ClInclude Include="StringHelper.h" />
<ClInclude Include="structs.h" />
<ClInclude Include="Tags.h" />
<ClInclude Include="TaskForce.h" />

View file

@ -282,6 +282,9 @@
<ClCompile Include="TextDrawer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="INIMeta.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="MissionEditor.rc">
@ -568,6 +571,12 @@
<ClInclude Include="IniHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StringHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="INIMeta.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="res\clifftoo.bmp">

View file

@ -28,8 +28,7 @@
#pragma once
#endif
#define VC_EXTRALEAN
#define NOMINMAX
#define VC_EXTRALEAN
#pragma warning(disable: 4503)
#pragma warning(disable: 4786)
@ -56,7 +55,7 @@
#include "resource.h"
#include "TipDlg.h"
using std::endl;
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ inserts additional declarations exactly above this line.

View file

@ -0,0 +1,25 @@
#pragma once
#include <afx.h>
#include <vector>
namespace utilities {
static std::vector<CString> split_string(const CString& pSource, TCHAR cSplit = ',')
{
std::vector<CString> ret;
CString tmp = pSource;
int pos = 0;
while ((pos = tmp.Find(cSplit)) != -1) {
ret.push_back(tmp.Left(pos));
tmp = tmp.Mid(pos + 1);
}
if (!tmp.IsEmpty()) {
ret.push_back(tmp);
}
return ret;
}
}

View file

@ -323,10 +323,10 @@ struct XCString
bUsedDefault = FALSE;
wString = new(WCHAR[len + 1]);
memset(wString, 0, (len + 1) * 2);
memset(wString, 0, (len + 1) * sizeof(WCHAR));
//MultiByteToWideChar(CP_ACP, WC_COMPOSITECHECK, cString, len, wString, len+1);
mbstowcs(wString, cString, len);
size_t convertedSize = 0;
mbstowcs_s(&convertedSize, wString, len + 1, cString, len);
}
void SetString(const WCHAR* wString, int len)
@ -358,7 +358,7 @@ struct XCString
CString cString;
WCHAR* wString;
BOOL bUsedDefault;
int len;
size_t len;
};

View file

@ -164,7 +164,7 @@ ProjectedVec TextDrawer::GetExtent(const std::string& text) const
cur.set(0, cur.y + ch + lineOffset);
} else if (c >= 32 && c <= 126) {
cur.x += cw;
maxpos.set(max(maxpos.x, cur.x), max(maxpos.y, cur.y + ch));
maxpos.set(std::max(maxpos.x, cur.x), std::max(maxpos.y, cur.y + ch));
}
}

File diff suppressed because it is too large Load diff

View file

@ -27,9 +27,45 @@
// ViewObjects.h : Header-Datei
//
#include <afxcview.h>
#include <unordered_set>
#define MAKE_MASK(refVal) 1 << static_cast<int>(refVal)
class TreeViewBuilder;
class CViewObjects;
class IniFileGroup;
using IgnoreSet = std::unordered_set<std::string>;
static const IgnoreSet CollectIgnoreSet();
extern CIniFile rules;
class TreeRoot {
friend class TreeViewBuilder;
friend class CViewObjects;
enum _ : int {
Nothing = -1,
Infantry,
Vehicle,
Aircraft,
Building,
Terrain,
Overlay,
Waypoint,
Celltag,
Basenode,
Tunnel,
Delete,
Owner,
PlayerLocation,
Ground,
Smudge,
Count,
Begin = 0,
};
};
enum class TreeViewTechnoType {
Set_None = -1,
Building = 0,
@ -62,6 +98,87 @@ inline bool operator&(TreeViewTechnoType lhs, TechnoTypeMask rhs)
return rhs & static_cast<TechnoTypeMask>(MAKE_MASK(lhs));
}
class GuessSideHelper {
public:
GuessSideHelper(const TreeViewBuilder& builder) :
builder(builder)
{}
const CString& GetSideName(const CString& regName, TreeViewTechnoType technoType, const CIniFile& inWhichIni = rules);
int GuessSide(const CString& pRegName, TreeViewTechnoType nType, const CIniFile& inWhichIni);
int guessGenericSide(const CString& typeId);
private:
int guessBuildingSide(const CString& typeId, const CIniFile& inWhichIni);
std::unordered_map<std::string, int> KnownItem;
const TreeViewBuilder& builder;
};
class TreeViewBuilder {
using houseMap = std::unordered_map<std::string, int>;
public:
struct CatetoryDefinition {
CString CategoryName;// or side name
TechnoTypeMask CategoryMask;
};
using mapSideNodeInfo = std::map<int, CatetoryDefinition>;
TreeViewBuilder(CTreeCtrl& tree,
const CIniFile& ini,
const IgnoreSet& ignoreSet,
const CString& theater,
const TheaterChar needed_terrain,
const HTREEITEM rootitems[]) :
tree(tree),
ini(ini),
theater(theater),
needed_terrain(needed_terrain),
rootitems(rootitems),
m_ignoreSet(ignoreSet),
m_owners(collectOwners()),
sideInfo(collectCategoryInfo())
{
updateTechnoItems();
}
const houseMap m_owners;
const mapSideNodeInfo sideInfo;
private:
static mapSideNodeInfo collectCategoryInfo();
static const houseMap collectOwners();
void updateTechnoItems();
void updateBuildingTypes(HTREEITEM parentNode);
void updateUnitTypes(HTREEITEM parentNode, const char* typeListId, TreeViewTechnoType technoType, int multiple);
const IgnoreSet& m_ignoreSet;
CTreeCtrl& tree;
const CIniFile& ini;
const CString& theater;
const TheaterChar needed_terrain;
const HTREEITEM* rootitems;
};
class TreeViewCategoryHandler {
using categoryNodeMap = std::unordered_map<std::string, HTREEITEM>;
public:
TreeViewCategoryHandler(CTreeCtrl& tree, HTREEITEM parentNode) :
tree(tree),
parentNode(parentNode)
{}
void Preallocate(const TreeViewBuilder::mapSideNodeInfo& sideInfo, TreeViewTechnoType type);
HTREEITEM GetOrAdd(const CString& name);
private:
CTreeCtrl& tree;
HTREEITEM parentNode;
categoryNodeMap structhouses;
};
/////////////////////////////////////////////////////////////////////////////
// Ansicht CViewObjects
@ -76,8 +193,6 @@ public:
// Operationen
public:
CTreeCtrl* tree;
BOOL m_ready;
void UpdateDialog();
// Überschreibungen
@ -110,6 +225,20 @@ private:
void HandleBrushSize(int iTile);
};
class IniMegaFile
{
friend class IniFileGroup;
public:
static IniFileGroup GetRules();
static bool IsNullOrEmpty(const CString& value) { return isNullOrEmpty(value); }
private:
static bool isNullOrEmpty(const CString& value);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}

View file

@ -11,6 +11,20 @@ AllowTunnels=yes
AllowUnidirectionalTunnels=yes
;ShowBuildingsWithToTile=no
[Sides]
0=Allied
1=Soviet
2=Yuri
3=安塔列星
4=科技功能建筑,1
5=地标建筑类,1
6=大城市建筑,1
7=中小城市建筑,1
8=村庄建筑,1
9=工业建筑,1
10=小型装饰摆件,1
11=中立特殊建筑,1
[ForceUnitPalettePrefix]
0=TIBTRE

View file

@ -1061,10 +1061,10 @@ No=否
NeedsYR=要用此地图进行游戏,需要尤里的复仇。
; name replacements
;N_AMRADR=American Air Force Command HQ
;N_SENGINEER=Soviet Engineer
;N_ENGINEER=Allied Engineer
;N_YENGINEER=Yuri Engineer
N_AMRADR=美国空指部
N_SENGINEER=苏军工程师
N_ENGINEER=盟军工程师
N_YENGINEER=尤里工程师
;N_SCHD=Deployed Siege Helicopter
;N_GACSPH=Chronosphere
;N_CALOND04=London Parliament

View file

@ -1280,10 +1280,10 @@ CString GetFreeID()
"Actions",
"AITriggerTypes",
};
if (find(std::begin(typeListSections), std::end(typeListSections), input) != std::end(typeListSections)) {
if (std::find(std::begin(typeListSections), std::end(typeListSections), input) != std::end(typeListSections)) {
return true;
}
if (find(std::begin(idListSections), std::end(idListSections), input) != std::end(idListSections)) {
if (std::find(std::begin(idListSections), std::end(idListSections), input) != std::end(idListSections)) {
return true;
}
return false;

View file

@ -25,6 +25,8 @@
#include <memory>
#include <array>
using std::string;
bool deleteFile(const std::string& u8FilePath);
// set the status bar text in the main dialog

View file

@ -78,7 +78,7 @@ inline CString GetUnitPictureFilename(LPCTSTR lpUnitName, DWORD dwPicIndex)
}
char n[50];
itoa(dwPicIndex, n, 10);
_itoa_s(dwPicIndex, n, 10);
if (pics.find(artname + n) != pics.end()) {
@ -195,7 +195,7 @@ inline CString SetParam(const CString& data, const int param, const CString& val
if (param < 0)
return data;
std::vector<CString> params = SplitParams(data);
params.resize(max(param + 1, static_cast<int>(params.size())));
params.resize(std::max(param + 1, static_cast<int>(params.size())));
params[param] = value;
return Join(",", params);
}

View file

@ -183,7 +183,7 @@ SMUDGE_INFO smudgeinfo[0x0F00];
#endif
/* error output */
ofstream errstream;
std::ofstream errstream;
/* the finalsun app object */
CFinalSunApp theApp;

View file

@ -114,7 +114,7 @@ extern SMUDGE_INFO smudgeinfo[0x0F00];
extern CFinalSunApp theApp;
/* error output */
extern ofstream errstream;
extern std::ofstream errstream;
// application path
extern char AppPath[MAX_PATH + 1];

View file

@ -0,0 +1,70 @@
#include "stdafx.h"
#include "../MissionEditor/INIMeta.h"
#if 1
TEST(IniFileGroup, ValidIniWithValidContentTest) {
CIniFile iniFile1;
CIniFile iniFile2;
const CString referenceList[] = {
CString("GANCST"),
CString("GAPOWR"),
CString("NACNST"),
CString("NAPOWR"),
};
iniFile1.SetString("BuildingTypes", "0", "GANCST");
iniFile1.SetString("BuildingTypes", "1", "GAPOWR");
iniFile1.SetString("GACNST", "Strength", "1000");
iniFile1.SetString("E2", "Strength", "100");
iniFile2.SetString("BuildingTypes", "2", "NACNST");
iniFile2.SetString("BuildingTypes", "3", "NAPOWR");
iniFile2.SetString("GACNST", "Strength", "2000");
iniFile2.SetString("NEWIFV", "Cost", "1000");
IniFileGroup group;
group.Append(iniFile1);
group.Append(iniFile2);
auto const bldTypes = group.GetSection("BuildingTypes");
auto idx = 0;
//for (auto const& [key, val] : bldTypes) {
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
auto const& [key, val] = *it;
EXPECT_EQ(val, referenceList[idx++]);
}
EXPECT_EQ(group.GetString("GACNST", "Strength"), "2000");
}
#endif
TEST(IniFileGroup, EmptyIniContentTest) {
CIniFile iniFile1;
CIniFile iniFile2;
IniFileGroup group;
group.Append(iniFile1);
group.Append(iniFile2);
auto const bldTypes = group.GetSection("BuildingTypes");
auto contentCount = 0;
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
auto const& [key, val] = *it;
cout << key << "=" << val << endl;
contentCount++;
}
EXPECT_EQ(contentCount, 0);
iniFile1.SetString("BuildingTypes", "0", "GANCST");
contentCount = 0;
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
auto const& [key, val] = *it;
cout << key << "=" << val << endl;
contentCount++;
}
EXPECT_EQ(contentCount, 1);
}

View file

@ -27,6 +27,9 @@
#include <iostream>
#include <afxwin.h>
using std::cout;
using std::endl;
#if !defined(ASSERT)
#define ASSERT(x) if (!(x)) throw("assertion failed");
#endif

View file

@ -102,9 +102,9 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;NOMINMAX;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;$(SolutionDir)MissionEditorPackLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Create</PrecompiledHeader>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<LanguageStandard>stdcpp20</LanguageStandard>
@ -133,11 +133,14 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\MissionEditor\IniFile.cpp" />
<ClCompile Include="..\MissionEditor\INIMeta.cpp" />
<ClCompile Include="CIni_Meta_Test.cpp" />
<ClCompile Include="CIni_Test.cpp" />
<ClCompile Include="UnitTest.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\MissionEditor\IniFile.h" />
<ClInclude Include="..\MissionEditor\INIMeta.h" />
<ClInclude Include="StdAfx.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View file

@ -24,6 +24,12 @@
<ClCompile Include="..\MissionEditor\IniFile.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="CIni_Meta_Test.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\MissionEditor\INIMeta.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="StdAfx.h">
@ -32,5 +38,8 @@
<ClInclude Include="..\MissionEditor\IniFile.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\MissionEditor\INIMeta.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>