Skip to content

Commit b31fc92

Browse files
authored
Merge pull request #253 from Jrius/clothingitem_py_improvements
pyClothingItem index safety and extra properties
2 parents 93fb48b + 83089d8 commit b31fc92

3 files changed

Lines changed: 87 additions & 21 deletions

File tree

Python/PRP/Avatar/pyClothingItem.cpp

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ PY_METHOD_VA(ClothingItem, getMesh,
3434
return nullptr;
3535
}
3636

37-
return pyPlasma_convert(self->fThis->getMesh(lod));
37+
if (lod >= 0 && lod < plClothingItem::LODLevels::kNumLODLevels)
38+
return pyPlasma_convert(self->fThis->getMesh(lod));
39+
40+
PyErr_SetString(PyExc_IndexError, "mesh index out of range");
41+
return nullptr;
3842
}
3943

4044
PY_METHOD_VA(ClothingItem, setMesh,
@@ -53,31 +57,49 @@ PY_METHOD_VA(ClothingItem, setMesh,
5357
return nullptr;
5458
}
5559

56-
self->fThis->setMesh(lod, *(key->fThis));
57-
Py_RETURN_NONE;
60+
if (lod >= 0 && lod < plClothingItem::LODLevels::kNumLODLevels) {
61+
self->fThis->setMesh(lod, *(key->fThis));
62+
Py_RETURN_NONE;
63+
}
64+
65+
PyErr_SetString(PyExc_IndexError, "mesh index out of range");
66+
return nullptr;
5867
}
5968

6069
PY_METHOD_VA(ClothingItem, getElementTexture,
6170
"Params: element, layer\n"
6271
"Gets the Key of the texture for the specified element and layer")
6372
{
64-
int element, layer;
65-
if (!PyArg_ParseTuple(args, "ii", &element, &layer)) {
73+
Py_ssize_t element, layer;
74+
if (!PyArg_ParseTuple(args, "nn", &element, &layer)) {
6675
PyErr_SetString(PyExc_TypeError, "getElementTexture expects int, int");
6776
return nullptr;
6877
}
6978

70-
return pyPlasma_convert(self->fThis->getElementTexture(element, layer));
79+
size_t element_s = size_t(element);
80+
size_t layer_s = size_t(layer);
81+
82+
if (element_s < self->fThis->getNumElements()) {
83+
if (layer_s < plClothingItem::kLayerMax) {
84+
return pyPlasma_convert(self->fThis->getElementTexture(element_s, layer_s));
85+
}
86+
87+
PyErr_SetString(PyExc_IndexError, "layer index out of range");
88+
return nullptr;
89+
}
90+
91+
PyErr_SetString(PyExc_IndexError, "element index out of range");
92+
return nullptr;
7193
}
7294

7395
PY_METHOD_VA(ClothingItem, setElementTexture,
7496
"Params: element idx, layer idx, texture\n"
7597
"Sets the texture of the specified element and layer")
7698
{
77-
int element, layer;
99+
Py_ssize_t element, layer;
78100
pyKey* key;
79101

80-
if (!PyArg_ParseTuple(args, "iiO", &element, &layer, &key)) {
102+
if (!PyArg_ParseTuple(args, "nnO", &element, &layer, &key)) {
81103
PyErr_SetString(PyExc_TypeError, "setElementTexture expects int, int, plKey");
82104
return nullptr;
83105
}
@@ -86,36 +108,62 @@ PY_METHOD_VA(ClothingItem, setElementTexture,
86108
return nullptr;
87109
}
88110

89-
self->fThis->setElementTexture(element, layer, *(key->fThis));
90-
Py_RETURN_NONE;
111+
size_t element_s = size_t(element);
112+
size_t layer_s = size_t(layer);
113+
114+
if (element_s < self->fThis->getNumElements()) {
115+
if (layer_s < plClothingItem::kLayerMax) {
116+
self->fThis->setElementTexture(element_s, layer_s, *(key->fThis));
117+
Py_RETURN_NONE;
118+
}
119+
120+
PyErr_SetString(PyExc_IndexError, "layer index out of range");
121+
return nullptr;
122+
}
123+
124+
PyErr_SetString(PyExc_IndexError, "element index out of range");
125+
return nullptr;
91126
}
92127

93128
PY_METHOD_VA(ClothingItem, getElementName,
94129
"Params: element idx\n"
95130
"Gets the name of the specified element")
96131
{
97-
int element;
98-
if (!PyArg_ParseTuple(args, "i", &element)) {
132+
Py_ssize_t element;
133+
if (!PyArg_ParseTuple(args, "n", &element)) {
99134
PyErr_SetString(PyExc_TypeError, "getElementName expects int");
100135
return nullptr;
101136
}
102137

103-
return pyPlasma_convert(self->fThis->getElementName(element));
138+
size_t element_s = size_t(element);
139+
140+
if (element_s < self->fThis->getNumElements())
141+
return pyPlasma_convert(self->fThis->getElementName(element_s));
142+
143+
PyErr_SetString(PyExc_IndexError, "element index out of range");
144+
return nullptr;
104145
}
105146

106147
PY_METHOD_VA(ClothingItem, setElementName,
107148
"Params: element idx, name\n"
108149
"Sets the name of the specified element")
109150
{
110-
int element;
151+
Py_ssize_t element;
111152
const char* name;
112-
if (!PyArg_ParseTuple(args, "is", &element, &name)) {
153+
if (!PyArg_ParseTuple(args, "ns", &element, &name)) {
113154
PyErr_SetString(PyExc_TypeError, "setElementName expects int, string");
114155
return nullptr;
115156
}
116157

117-
self->fThis->setElementName(element, name);
118-
Py_RETURN_NONE;
158+
size_t element_s = size_t(element);
159+
160+
if (element_s < self->fThis->getNumElements()) {
161+
self->fThis->setElementName(element_s, name);
162+
Py_RETURN_NONE;
163+
}
164+
165+
PyErr_SetString(PyExc_IndexError, "element index out of range");
166+
return nullptr;
119167
}
120168

121169
PY_METHOD_VA(ClothingItem, addElement,
@@ -136,13 +184,21 @@ PY_METHOD_VA(ClothingItem, delElement,
136184
"Params: element idx\n"
137185
"Remove an element from the clothingItem")
138186
{
139-
int idx;
140-
if (!PyArg_ParseTuple(args, "i", &idx)) {
187+
Py_ssize_t idx;
188+
if (!PyArg_ParseTuple(args, "n", &idx)) {
141189
PyErr_SetString(PyExc_TypeError, "delElement expects an int");
142190
return nullptr;
143191
}
144-
self->fThis->delElement(idx);
145-
Py_RETURN_NONE;
192+
193+
size_t idx_s = size_t(idx);
194+
195+
if (idx_s < self->fThis->getNumElements()) {
196+
self->fThis->delElement(idx_s);
197+
Py_RETURN_NONE;
198+
}
199+
200+
PyErr_SetString(PyExc_IndexError, "element index out of range");
201+
return nullptr;
146202
}
147203

148204
PY_METHOD_NOARGS(ClothingItem, clearElements,
@@ -176,6 +232,7 @@ PY_PROPERTY(plKey, ClothingItem, icon, getIcon, setIcon)
176232
PY_PROPERTY(plKey, ClothingItem, accessory, getAccessory, setAccessory)
177233
PY_PROPERTY(hsColorRGBA, ClothingItem, defaultTint1, getDefaultTint1, setDefaultTint1)
178234
PY_PROPERTY(hsColorRGBA, ClothingItem, defaultTint2, getDefaultTint2, setDefaultTint2)
235+
PY_PROPERTY_RO(ClothingItem, numElements, getNumElements)
179236

180237
PyGetSetDef pyClothingItem_GetSet[] = {
181238
pyClothingItem_itemName_getset,
@@ -189,6 +246,7 @@ PyGetSetDef pyClothingItem_GetSet[] = {
189246
pyClothingItem_accessory_getset,
190247
pyClothingItem_defaultTint1_getset,
191248
pyClothingItem_defaultTint2_getset,
249+
pyClothingItem_numElements_getset,
192250
PY_GETSET_TERMINATOR
193251
};
194252

@@ -207,6 +265,7 @@ PY_PLASMA_TYPE_INIT(ClothingItem)
207265
PY_TYPE_ADD_CONST(ClothingItem, "kLODHigh", plClothingItem::kLODHigh);
208266
PY_TYPE_ADD_CONST(ClothingItem, "kLODMedium", plClothingItem::kLODMedium);
209267
PY_TYPE_ADD_CONST(ClothingItem, "kLODLow", plClothingItem::kLODLow);
268+
PY_TYPE_ADD_CONST(ClothingItem, "kNumLODLevels", plClothingItem::kNumLODLevels);
210269

211270
/* ClothingLayer Konstants */
212271
PY_TYPE_ADD_CONST(ClothingItem, "kLayerBase", plClothingItem::kLayerBase);
@@ -219,6 +278,7 @@ PY_PLASMA_TYPE_INIT(ClothingItem)
219278
PY_TYPE_ADD_CONST(ClothingItem, "kLayerSkinBlend6", plClothingItem::kLayerSkinBlend6);
220279
PY_TYPE_ADD_CONST(ClothingItem, "kLayerTint1", plClothingItem::kLayerTint1);
221280
PY_TYPE_ADD_CONST(ClothingItem, "kLayerTint2", plClothingItem::kLayerTint2);
281+
PY_TYPE_ADD_CONST(ClothingItem, "kLayerMax", plClothingItem::kLayerMax);
222282

223283
/* Tileset Konstants */
224284
PY_TYPE_ADD_CONST(ClothingItem, "kSetShirt", plClothingItem::kSetShirt);

Python/PyHSPlasma.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,7 @@ class plClothingItem(hsKeyedObject):
16711671
kLODLow: int = ...
16721672
kLODMedium: int = ...
16731673
kLayerBase: int = ...
1674+
kLayerMax: int = ...
16741675
kLayerSkin: int = ...
16751676
kLayerSkinBlend1: int = ...
16761677
kLayerSkinBlend2: int = ...
@@ -1680,6 +1681,7 @@ class plClothingItem(hsKeyedObject):
16801681
kLayerSkinBlend6: int = ...
16811682
kLayerTint1: int = ...
16821683
kLayerTint2: int = ...
1684+
kNumLODLevels: int = ...
16831685
kSetBackpack: int = ...
16841686
kSetEye: int = ...
16851687
kSetFace: int = ...
@@ -1708,6 +1710,7 @@ class plClothingItem(hsKeyedObject):
17081710
group: int = ...
17091711
icon: Optional[plKey[plMipmap]] = ...
17101712
itemName: str = ...
1713+
numElements: int = ...
17111714
sortOrder: int = ...
17121715
tileset: int = ...
17131716
type: int = ...

core/PRP/Avatar/plClothingItem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ class HSPLASMA_EXPORT plClothingItem : public hsKeyedObject
198198
/** Add a named element to the clothing item. */
199199
void addElement(const ST::string& elementName);
200200

201+
/** Return the number of elements in the clothing item. */
202+
size_t getNumElements() const { return fElementNames.size(); }
203+
201204
/**
202205
* Sets the texture for element number \a element, at layer \a layer
203206
* to \a texture.

0 commit comments

Comments
 (0)