|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00062 #include <plugin_python.h> 00063 00070 static void *attr_list_len_ptr(Atrinik_AttrList *al) 00071 { 00072 if (al->field == FIELDTYPE_KNOWN_SPELLS) 00073 { 00074 return (uint16 *) ((void *) ((char *) al->ptr + offsetof(player, nrofknownspells))); 00075 } 00076 else if (al->field == FIELDTYPE_CMD_PERMISSIONS) 00077 { 00078 return (int *) ((void *) ((char *) al->ptr + offsetof(player, num_cmd_permissions))); 00079 } 00080 else if (al->field == FIELDTYPE_FACTIONS) 00081 { 00082 return (int *) ((void *) ((char *) al->ptr + offsetof(player, num_faction_ids))); 00083 } 00084 00085 /* Not reached. */ 00086 return NULL; 00087 } 00088 00093 static unsigned PY_LONG_LONG attr_list_len(Atrinik_AttrList *al) 00094 { 00095 if (al->field == FIELDTYPE_KNOWN_SPELLS) 00096 { 00097 return *(uint16 *) attr_list_len_ptr(al); 00098 } 00099 else if (al->field == FIELDTYPE_CMD_PERMISSIONS || al->field == FIELDTYPE_FACTIONS) 00100 { 00101 return *(int *) attr_list_len_ptr(al); 00102 } 00103 00104 return 0; 00105 } 00106 00112 static PyObject *attr_list_get(Atrinik_AttrList *al, void *idx) 00113 { 00114 void *ptr; 00115 fields_struct field = {"xxx", 0, 0, 0, 0}; 00116 00117 ptr = (void *) ((char *) al->ptr + al->offset); 00118 00119 /* Known spells; cast to sint16. */ 00120 if (al->field == FIELDTYPE_KNOWN_SPELLS) 00121 { 00122 field.type = FIELDTYPE_SINT16; 00123 ptr = &((sint16 *) ptr)[*(unsigned PY_LONG_LONG *) idx]; 00124 } 00125 else if (al->field == FIELDTYPE_CMD_PERMISSIONS) 00126 { 00127 field.type = FIELDTYPE_CSTR; 00128 ptr = &(*(char ***) ptr)[*(unsigned PY_LONG_LONG *) idx]; 00129 } 00130 else if (al->field == FIELDTYPE_FACTIONS) 00131 { 00132 unsigned PY_LONG_LONG len, i; 00133 00134 len = attr_list_len(al); 00135 field.type = FIELDTYPE_SINT64; 00136 00137 for (i = 0; i < len; i++) 00138 { 00139 if (!strcmp((const char *) (char *) idx, *(const char **) (&(*(shstr ***) ptr)[i]))) 00140 { 00141 ptr = &(*(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))))[i]; 00142 return generic_field_getter(&field, ptr); 00143 } 00144 } 00145 00146 Py_INCREF(Py_None); 00147 return Py_None; 00148 } 00149 00150 return generic_field_getter(&field, ptr); 00151 } 00152 00158 static int attr_list_contains(Atrinik_AttrList *al, PyObject *value) 00159 { 00160 unsigned PY_LONG_LONG i, len; 00161 PyObject *check; 00162 00163 if (al->field == FIELDTYPE_FACTIONS) 00164 { 00165 PyErr_SetString(PyExc_NotImplementedError, "Attribute list does not implement contains method."); 00166 return -1; 00167 } 00168 00169 len = attr_list_len(al); 00170 00171 for (i = 0; i < len; i++) 00172 { 00173 /* attr_list_get() creates a new reference, so make sure to decrease 00174 * it later. */ 00175 check = attr_list_get(al, &i); 00176 00177 /* Compare the two objects... */ 00178 if (PyObject_RichCompareBool(check, value, Py_EQ) == 1) 00179 { 00180 Py_DECREF(check); 00181 return 1; 00182 } 00183 00184 Py_DECREF(check); 00185 } 00186 00187 return 0; 00188 } 00189 00196 static int attr_list_set(Atrinik_AttrList *al, void *idx, PyObject *value) 00197 { 00198 unsigned PY_LONG_LONG len; 00199 void *ptr; 00200 fields_struct field = {"xxx", 0, 0, 0, 0}; 00201 int ret; 00202 unsigned PY_LONG_LONG i; 00203 00204 /* Get the current length of the list. */ 00205 len = attr_list_len(al); 00206 ptr = (void *) ((char *) al->ptr + al->offset); 00207 00208 /* Known spells array. */ 00209 if (al->field == FIELDTYPE_KNOWN_SPELLS) 00210 { 00211 i = *(unsigned PY_LONG_LONG *) idx; 00212 00213 /* Known spells array is fixed size; cannot go over the maximum. */ 00214 if (len >= sizeof(((player *) NULL)->known_spells)) 00215 { 00216 PyErr_SetString(PyExc_OverflowError, "Overflow error."); 00217 return -1; 00218 } 00219 00220 /* Make sure the value is not already in the array, to prevent the 00221 * the array from filling up with duplicate entries. */ 00222 if (attr_list_contains(al, value)) 00223 { 00224 PyErr_SetString(PyExc_ValueError, "Value is already inside the array."); 00225 return -1; 00226 } 00227 00228 field.type = FIELDTYPE_SINT16; 00229 ptr = &((sint16 *) ptr)[i]; 00230 } 00231 /* Command permissions. */ 00232 else if (al->field == FIELDTYPE_CMD_PERMISSIONS) 00233 { 00234 i = *(unsigned PY_LONG_LONG *) idx; 00235 00236 /* Over the maximum size; resize the array, as it's dynamic. */ 00237 if (i >= len) 00238 { 00239 /* Increase the number of commands... */ 00240 (*(int *) attr_list_len_ptr(al))++; 00241 /* And resize it. */ 00242 *(char ***) ((void *) ((char *) al->ptr + al->offset)) = realloc(*(char ***) ((void *) ((char *) al->ptr + al->offset)), sizeof(char *) * attr_list_len(al)); 00243 /* Make sure ptr points to the right memory... */ 00244 ptr = (void *) ((char *) al->ptr + al->offset); 00245 /* NULL the new member. */ 00246 (*(char ***) ptr)[i] = NULL; 00247 } 00248 00249 field.type = FIELDTYPE_CSTR; 00250 ptr = &(*(char ***) ptr)[i]; 00251 } 00252 /* Factions. */ 00253 else if (al->field == FIELDTYPE_FACTIONS) 00254 { 00255 field.type = FIELDTYPE_SINT64; 00256 00257 /* Try to find an existing entry. */ 00258 for (i = 0; i < len; i++) 00259 { 00260 if (!strcmp((const char *) (char *) idx, *(const char **) (&(*(shstr ***) ptr)[i]))) 00261 { 00262 break; 00263 } 00264 } 00265 00266 /* Doesn't exist, create it. */ 00267 if (i == len) 00268 { 00269 (*(int *) attr_list_len_ptr(al))++; 00270 *(shstr ***) ((void *) ((char *) al->ptr + al->offset)) = realloc(*(shstr ***) ((void *) ((char *) al->ptr + al->offset)), sizeof(shstr *) * attr_list_len(al)); 00271 *(shstr **) (&(*(shstr ***) ptr)[i]) = hooks->add_string((const char *) (char *) idx); 00272 *(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))) = realloc(*(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))), sizeof(sint64) * attr_list_len(al)); 00273 /* Make sure ptr points to the right memory... */ 00274 ptr = (void *) ((char *) al->ptr + offsetof(player, faction_reputation)); 00275 /* NULL the new member. */ 00276 (*(sint64 **) ptr)[i] = 0; 00277 } 00278 00279 ptr = &(*(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))))[i]; 00280 } 00281 else 00282 { 00283 PyErr_SetString(PyExc_NotImplementedError, "The attribute list does not implement support for write operations."); 00284 return -1; 00285 } 00286 00287 ret = generic_field_setter(&field, ptr, value); 00288 00289 /* Success! */ 00290 if (ret == 0) 00291 { 00292 /* Increased known spells successfully, so increase the total 00293 * number of known spells as well (if we were adding a new one, 00294 * that is). */ 00295 if (al->field == FIELDTYPE_KNOWN_SPELLS && i >= len) 00296 { 00297 (*(uint16 *) attr_list_len_ptr(al))++; 00298 } 00299 } 00300 /* Failure; overflow, invalid value or some other kind of error. */ 00301 else if (ret == -1) 00302 { 00303 if (i >= len) 00304 { 00305 /* We tried to add a new command permission and we have already 00306 * resized the array, so shrink it back now, as we failed. */ 00307 if (al->field == FIELDTYPE_CMD_PERMISSIONS) 00308 { 00309 /* Decrease the number of commands... */ 00310 (*(int *) attr_list_len_ptr(al))--; 00311 /* And resize it. */ 00312 *(char ***) ((void *) ((char *) al->ptr + al->offset)) = realloc(*(char ***) ((void *) ((char *) al->ptr + al->offset)), sizeof(char *) * attr_list_len(al)); 00313 } 00314 else if (al->field == FIELDTYPE_FACTIONS) 00315 { 00316 (*(int *) attr_list_len_ptr(al))--; 00317 *(shstr ***) ((void *) ((char *) al->ptr + al->offset)) = realloc(*(shstr ***) ((void *) ((char *) al->ptr + al->offset)), sizeof(shstr *) * attr_list_len(al)); 00318 *(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))) = realloc(*(sint64 **) ((void *) ((char *) al->ptr + offsetof(player, faction_reputation))), sizeof(sint64) * attr_list_len(al)); 00319 } 00320 } 00321 } 00322 00323 return ret; 00324 } 00325 00332 static PyObject *__getitem__(Atrinik_AttrList *al, PyObject *key) 00333 { 00334 void *idx; 00335 00336 if (al->field == FIELDTYPE_FACTIONS) 00337 { 00338 char *cstr; 00339 00340 if (!PyString_Check(key)) 00341 { 00342 PyErr_SetString(PyExc_ValueError, "__getitem__() failed; key must be a string."); 00343 return NULL; 00344 } 00345 00346 cstr = PyString_AsString(key); 00347 idx = cstr; 00348 } 00349 else 00350 { 00351 unsigned PY_LONG_LONG i, len; 00352 00353 /* The key must be an integer. */ 00354 if (!PyInt_Check(key)) 00355 { 00356 PyErr_SetString(PyExc_ValueError, "__getitem__() failed; key must be an integer."); 00357 return NULL; 00358 } 00359 00360 i = PyLong_AsUnsignedLongLong(key); 00361 00362 if (PyErr_Occurred()) 00363 { 00364 PyErr_SetString(PyExc_OverflowError, "__getitem__() failed; key's integer value is too large."); 00365 return NULL; 00366 } 00367 00368 len = attr_list_len(al); 00369 00370 if (i > len) 00371 { 00372 PyErr_Format(PyExc_ValueError, "__getitem__() failed; requested index (%"FMT64U") too big (len: %"FMT64U").", (uint64) i, (uint64) len); 00373 return NULL; 00374 } 00375 00376 idx = &i; 00377 } 00378 00379 return attr_list_get(al, idx); 00380 } 00381 00390 static PyObject *append(Atrinik_AttrList *al, PyObject *value) 00391 { 00392 unsigned PY_LONG_LONG i; 00393 00394 if (al->field == FIELDTYPE_FACTIONS) 00395 { 00396 PyErr_SetString(PyExc_NotImplementedError, "This attribute list does not implement append method."); 00397 return NULL; 00398 } 00399 00400 i = attr_list_len(al); 00401 attr_list_set(al, &i, value); 00402 00403 Py_INCREF(Py_None); 00404 return Py_None; 00405 } 00406 00408 static PyMethodDef methods[] = 00409 { 00410 {"__getitem__", (PyCFunction) __getitem__, METH_O | METH_COEXIST, 0}, 00411 {"append", (PyCFunction) append, METH_O, 0}, 00412 {NULL, NULL, 0, 0} 00413 }; 00414 00415 static int InternalCompare(Atrinik_AttrList *left, Atrinik_AttrList *right) 00416 { 00417 return (left->field < right->field ? -1 : (left->field == right->field ? 0 : 1)); 00418 } 00419 00420 static PyObject *RichCompare(Atrinik_AttrList *left, Atrinik_AttrList *right, int op) 00421 { 00422 if (!left || !right || !PyObject_TypeCheck((PyObject *) left, &Atrinik_AttrListType) || !PyObject_TypeCheck((PyObject *) right, &Atrinik_AttrListType)) 00423 { 00424 Py_INCREF(Py_NotImplemented); 00425 return Py_NotImplemented; 00426 } 00427 00428 return generic_rich_compare(op, InternalCompare(left, right)); 00429 } 00430 00435 static PyObject *iter(PyObject *seq) 00436 { 00437 Atrinik_AttrList *al, *orig_al = (Atrinik_AttrList *) seq; 00438 00439 al = PyObject_NEW(Atrinik_AttrList, &Atrinik_AttrListType); 00440 al->iter = 0; 00441 al->ptr = orig_al->ptr; 00442 al->offset = orig_al->offset; 00443 al->field = orig_al->field; 00444 00445 return (PyObject *) al; 00446 } 00447 00452 static PyObject *iternext(Atrinik_AttrList *al) 00453 { 00454 /* Possible to continue iteration? */ 00455 if (al->iter < attr_list_len(al)) 00456 { 00457 void *idx; 00458 00459 al->iter++; 00460 00461 if (al->field == FIELDTYPE_FACTIONS) 00462 { 00463 char *key = *(char **) (&(*(shstr ***) (void *) ((char *) al->ptr + al->offset))[al->iter - 1]); 00464 00465 idx = key; 00466 } 00467 else 00468 { 00469 unsigned PY_LONG_LONG i = al->iter - 1; 00470 00471 idx = &i; 00472 } 00473 00474 return attr_list_get(al, idx); 00475 } 00476 00477 /* Stop iteration. */ 00478 return NULL; 00479 } 00480 00487 static Py_ssize_t __len__(Atrinik_AttrList *al) 00488 { 00489 return attr_list_len(al); 00490 } 00491 00496 static int __setitem__(Atrinik_AttrList *al, PyObject *key, PyObject *value) 00497 { 00498 void *idx; 00499 00500 if (al->field == FIELDTYPE_FACTIONS) 00501 { 00502 idx = PyString_AsString(key); 00503 } 00504 else 00505 { 00506 unsigned PY_LONG_LONG i = PyLong_AsUnsignedLongLong(key); 00507 idx = &i; 00508 } 00509 00510 return attr_list_set(al, idx, value); 00511 } 00512 00517 static int __contains__(Atrinik_AttrList *al, PyObject *value) 00518 { 00519 return attr_list_contains(al, value); 00520 } 00521 00523 static PySequenceMethods SequenceMethods = 00524 { 00525 (lenfunc) __len__, 00526 NULL, NULL, NULL, NULL, NULL, NULL, 00527 (objobjproc) __contains__, 00528 NULL, NULL 00529 }; 00530 00534 static PyMappingMethods MappingMethods = 00535 { 00536 (lenfunc) __len__, 00537 (binaryfunc) __getitem__, 00538 (objobjargproc) __setitem__, 00539 }; 00540 00542 PyTypeObject Atrinik_AttrListType = 00543 { 00544 #ifdef IS_PY3K 00545 PyVarObject_HEAD_INIT(NULL, 0) 00546 #else 00547 PyObject_HEAD_INIT(NULL) 00548 0, 00549 #endif 00550 "Atrinik.AttrList", 00551 sizeof(Atrinik_AttrList), 00552 0, 00553 NULL, 00554 NULL, NULL, NULL, 00555 #ifdef IS_PY3K 00556 NULL, 00557 #else 00558 (cmpfunc) InternalCompare, 00559 #endif 00560 NULL, 00561 0, 00562 &SequenceMethods, 00563 &MappingMethods, 00564 0, 0, 00565 NULL, 00566 0, 0, 0, 00567 Py_TPFLAGS_DEFAULT, 00568 "Atrinik attr lists", 00569 NULL, NULL, 00570 (richcmpfunc) RichCompare, 00571 0, 00572 (getiterfunc) iter, 00573 (iternextfunc) iternext, 00574 methods, 00575 0, 00576 NULL, 00577 0, 0, 0, 0, 0, 0, 0, 00578 NULL, 00579 0, 0, 0, 0, 0, 0, 0, 0 00580 #ifndef IS_PY_LEGACY 00581 , 0 00582 #endif 00583 }; 00584 00589 int Atrinik_AttrList_init(PyObject *module) 00590 { 00591 Atrinik_AttrListType.tp_new = PyType_GenericNew; 00592 00593 if (PyType_Ready(&Atrinik_AttrListType) < 0) 00594 { 00595 return 0; 00596 } 00597 00598 Py_INCREF(&Atrinik_AttrListType); 00599 PyModule_AddObject(module, "AtrrList", (PyObject *) &Atrinik_AttrListType); 00600 00601 return 1; 00602 } 00603 00611 PyObject *wrap_attr_list(void *ptr, size_t offset, field_type field) 00612 { 00613 Atrinik_AttrList *wrapper; 00614 00615 wrapper = PyObject_NEW(Atrinik_AttrList, &Atrinik_AttrListType); 00616 00617 if (wrapper) 00618 { 00619 wrapper->ptr = ptr; 00620 wrapper->offset = offset; 00621 wrapper->field = field; 00622 } 00623 00624 return (PyObject *) wrapper; 00625 }
1.7.4