Properly kill gameobjects, sprites, physics shapes
This commit is contained in:
parent
e0b7d6459d
commit
d2cbc61164
|
@ -41,10 +41,12 @@ void phys2d_shape_apply(struct phys2d_shape *shape)
|
||||||
cpShapeSetElasticity(shape->shape, id2go(shape->go)->e);
|
cpShapeSetElasticity(shape->shape, id2go(shape->go)->e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_phys2dshape(struct phys2d_shape *shape, int go)
|
void init_phys2dshape(struct phys2d_shape *shape, int go, void *data)
|
||||||
{
|
{
|
||||||
shape->go = go;
|
shape->go = go;
|
||||||
cpShapeSetCollisionType(shape->shape, id2go(go));
|
shape->data = data;
|
||||||
|
cpShapeSetCollisionType(shape->shape, go);
|
||||||
|
cpShapeSetUserData(shape->shape, shape);
|
||||||
phys2d_shape_apply(shape);
|
phys2d_shape_apply(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +64,8 @@ struct phys2d_circle *Make2DCircle(int go)
|
||||||
new->offset[1] = 0.f;
|
new->offset[1] = 0.f;
|
||||||
|
|
||||||
new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero));
|
new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero));
|
||||||
init_phys2dshape(&new->shape, go);
|
new->shape.debugdraw = phys2d_dbgdrawcircle;
|
||||||
|
init_phys2dshape(&new->shape, go, new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +85,6 @@ void circle_gui(struct phys2d_circle *circle)
|
||||||
|
|
||||||
void phys2d_dbgdrawcpcirc(cpCircleShape *c)
|
void phys2d_dbgdrawcpcirc(cpCircleShape *c)
|
||||||
{
|
{
|
||||||
YughInfo("DRAW CIRCLE");
|
|
||||||
cpVect pos = cpBodyGetPosition(cpShapeGetBody(c));
|
cpVect pos = cpBodyGetPosition(cpShapeGetBody(c));
|
||||||
cpVect offset = cpCircleShapeGetOffset(c);
|
cpVect offset = cpCircleShapeGetOffset(c);
|
||||||
float radius = cpCircleShapeGetRadius(c);
|
float radius = cpCircleShapeGetRadius(c);
|
||||||
|
@ -93,7 +95,6 @@ void phys2d_dbgdrawcpcirc(cpCircleShape *c)
|
||||||
|
|
||||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle)
|
void phys2d_dbgdrawcircle(struct phys2d_circle *circle)
|
||||||
{
|
{
|
||||||
YughInfo("Drawing a circle");
|
|
||||||
phys2d_dbgdrawcpcirc((cpCircleShape *)circle->shape.shape);
|
phys2d_dbgdrawcpcirc((cpCircleShape *)circle->shape.shape);
|
||||||
|
|
||||||
cpVect p = cpBodyGetPosition(cpShapeGetBody(circle->shape.shape));
|
cpVect p = cpBodyGetPosition(cpShapeGetBody(circle->shape.shape));
|
||||||
|
@ -118,7 +119,8 @@ struct phys2d_segment *Make2DSegment(int go)
|
||||||
new->b[1] = 0.f;
|
new->b[1] = 0.f;
|
||||||
|
|
||||||
new->shape.shape = cpSpaceAddShape(space, cpSegmentShapeNew(id2go(go)->body, cpvzero, cpvzero, new->thickness));
|
new->shape.shape = cpSpaceAddShape(space, cpSegmentShapeNew(id2go(go)->body, cpvzero, cpvzero, new->thickness));
|
||||||
init_phys2dshape(&new->shape, go);
|
new->shape.debugdraw = phys2d_dbgdrawseg;
|
||||||
|
init_phys2dshape(&new->shape, go, new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +152,8 @@ struct phys2d_box *Make2DBox(int go)
|
||||||
new->offset[1] = 0.f;
|
new->offset[1] = 0.f;
|
||||||
|
|
||||||
new->shape.shape = cpSpaceAddShape(space, cpBoxShapeNew(id2go(go)->body, new->w, new->h, new->r));
|
new->shape.shape = cpSpaceAddShape(space, cpBoxShapeNew(id2go(go)->body, new->w, new->h, new->r));
|
||||||
init_phys2dshape(&new->shape, go);
|
new->shape.debugdraw = phys2d_dbgdrawbox;
|
||||||
|
init_phys2dshape(&new->shape, go, new);
|
||||||
phys2d_applybox(new);
|
phys2d_applybox(new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
|
@ -182,7 +185,8 @@ struct phys2d_poly *Make2DPoly(int go)
|
||||||
|
|
||||||
cpTransform T = { 0 };
|
cpTransform T = { 0 };
|
||||||
new->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(id2go(go)->body, 0, NULL, T, new->radius));
|
new->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(id2go(go)->body, 0, NULL, T, new->radius));
|
||||||
init_phys2dshape(&new->shape, go);
|
init_phys2dshape(&new->shape, go, new);
|
||||||
|
new->shape.debugdraw = phys2d_dbgdrawpoly;
|
||||||
phys2d_applypoly(new);
|
phys2d_applypoly(new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
|
@ -453,16 +457,15 @@ void register_collide(void *sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static cpBool script_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) {
|
static cpBool script_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) {
|
||||||
struct gameobject *go = data;
|
|
||||||
|
|
||||||
cpBody *body1;
|
cpBody *body1;
|
||||||
cpBody *body2;
|
cpBody *body2;
|
||||||
cpArbiterGetBodies(arb, &body1, &body2);
|
cpArbiterGetBodies(arb, &body1, &body2);
|
||||||
|
|
||||||
struct gameobject *g2 = cpBodyGetUserData(body2);
|
int g1 = cpBodyGetUserData(body1);
|
||||||
|
int g2 = cpBodyGetUserData(body2);
|
||||||
|
|
||||||
duk_push_heapptr(duk, go->cbs.begin.fn);
|
duk_push_heapptr(duk, id2go(g1)->cbs.begin.fn);
|
||||||
duk_push_heapptr(duk, go->cbs.begin.obj);
|
duk_push_heapptr(duk, id2go(g1)->cbs.begin.obj);
|
||||||
|
|
||||||
int obj = duk_push_object(duk);
|
int obj = duk_push_object(duk);
|
||||||
|
|
||||||
|
@ -492,10 +495,9 @@ static void s7_phys_cb_separate(cpArbiter *Arb, cpSpace *space, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void phys2d_add_handler_type(int cmd, int go, struct callee c) {
|
void phys2d_add_handler_type(int cmd, int go, struct callee c) {
|
||||||
/*
|
|
||||||
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
|
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
|
||||||
|
|
||||||
handler->userData = id2go(go);
|
handler->userData = go;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -514,5 +516,5 @@ void phys2d_add_handler_type(int cmd, int go, struct callee c) {
|
||||||
//go->cbs->separate = cb;
|
//go->cbs->separate = cb;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@
|
||||||
#include <chipmunk/chipmunk.h>
|
#include <chipmunk/chipmunk.h>
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
|
|
||||||
extern cpBody *ballBody;
|
|
||||||
extern float phys2d_gravity;
|
extern float phys2d_gravity;
|
||||||
extern int physOn;
|
extern int physOn;
|
||||||
extern cpSpace *space;
|
extern cpSpace *space;
|
||||||
|
@ -12,6 +11,8 @@ extern cpSpace *space;
|
||||||
struct phys2d_shape {
|
struct phys2d_shape {
|
||||||
cpShape *shape;
|
cpShape *shape;
|
||||||
int go;
|
int go;
|
||||||
|
void *data;
|
||||||
|
void (*debugdraw)(void *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct phys2d_circle {
|
struct phys2d_circle {
|
||||||
|
|
|
@ -100,7 +100,7 @@ duk_ret_t duk_cmd(duk_context *duk) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
|
remove_pawn(duk_get_heapptr(duk, 1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11:
|
case 11:
|
||||||
|
@ -145,7 +145,7 @@ duk_ret_t duk_register_collide(duk_context *duk) {
|
||||||
struct callee c = {fn, obj};
|
struct callee c = {fn, obj};
|
||||||
YughInfo("Registering ...");
|
YughInfo("Registering ...");
|
||||||
|
|
||||||
phys2d_add_handler_type(0, get_gameobject_from_id(go), c);
|
phys2d_add_handler_type(0, go, c);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ duk_ret_t duk_sprite(duk_context *duk) {
|
||||||
int id = duk_to_int(duk, 1);
|
int id = duk_to_int(duk, 1);
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 0:
|
case 0: break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,6 @@ duk_ret_t duk_make_sprite(duk_context *duk) {
|
||||||
sp->pos[0] = pos.x;
|
sp->pos[0] = pos.x;
|
||||||
sp->pos[1] = pos.y;
|
sp->pos[1] = pos.y;
|
||||||
|
|
||||||
|
|
||||||
duk_push_int(duk, sprite);
|
duk_push_int(duk, sprite);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
struct gameobject *gameobjects = NULL;
|
struct gameobject *gameobjects = NULL;
|
||||||
struct gameobject *first = NULL;
|
static int first = -1;
|
||||||
|
|
||||||
const int nameBuf[MAXNAME] = { 0 };
|
const int nameBuf[MAXNAME] = { 0 };
|
||||||
const int prefabNameBuf[MAXNAME] = { 0 };
|
const int prefabNameBuf[MAXNAME] = { 0 };
|
||||||
|
@ -66,46 +66,66 @@ int MakeGameobject()
|
||||||
struct gameobject go = {
|
struct gameobject go = {
|
||||||
.scale = 1.f,
|
.scale = 1.f,
|
||||||
.bodytype = CP_BODY_TYPE_STATIC,
|
.bodytype = CP_BODY_TYPE_STATIC,
|
||||||
.mass = 1.f
|
.mass = 1.f,
|
||||||
|
.next = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
|
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
|
||||||
|
|
||||||
struct gameobject *tar;
|
|
||||||
|
|
||||||
int retid;
|
int retid;
|
||||||
|
|
||||||
if (!first) {
|
if (first<0) {
|
||||||
arrput(gameobjects, go);
|
arrput(gameobjects, go);
|
||||||
tar = &arrlast(gameobjects);
|
retid = arrlast(gameobjects).id = arrlen(gameobjects)-1;
|
||||||
retid = arrlen(gameobjects)-1;
|
|
||||||
tar->id = retid;
|
|
||||||
} else {
|
} else {
|
||||||
|
retid = first;
|
||||||
retid = first->id;
|
first = id2go(first)->next;
|
||||||
struct gameobject *next = first->next;
|
*id2go(retid) = go;
|
||||||
YughInfo("Created in slot %d.", retid);
|
|
||||||
tar = first;
|
|
||||||
*first = go;
|
|
||||||
first->id = retid;
|
|
||||||
first = next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpBodySetUserData(go.body, tar);
|
cpBodySetUserData(go.body, retid);
|
||||||
|
|
||||||
YughInfo("Made game object with ID ===== %d", retid);
|
|
||||||
return retid;
|
return retid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
|
||||||
|
struct phys2d_shape *s = cpShapeGetUserData(shape);
|
||||||
|
free(s->data);
|
||||||
|
cpSpaceRemoveShape(space, shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Really more of a "mark for deletion" ... */
|
||||||
void gameobject_delete(int id)
|
void gameobject_delete(int id)
|
||||||
{
|
{
|
||||||
YughInfo("Deleting gameobject with id %d.", id);
|
id2go(id)->next = first;
|
||||||
struct gameobject *go = id2go(id);
|
first = id;
|
||||||
cpSpaceRemoveBody(space, go->body);
|
}
|
||||||
go->next = first;
|
|
||||||
first = go;
|
|
||||||
|
|
||||||
YughInfo("Did it to %d.", first->id);
|
void gameobject_clean(int id) {
|
||||||
|
if (id < 0) {
|
||||||
|
YughError("Tried to clean ID %d.", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct gameobject *go = id2go(id);
|
||||||
|
cpBodyEachShape(go->body, rm_body_shapes, NULL);
|
||||||
|
cpSpaceRemoveBody(space, go->body);
|
||||||
|
go->body = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int last_cleaned = -1;
|
||||||
|
|
||||||
|
void gameobjects_cleanup() {
|
||||||
|
if (first < 0) {
|
||||||
|
last_cleaned = first;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clean = first;
|
||||||
|
while (clean != last_cleaned) {
|
||||||
|
gameobject_clean(clean);
|
||||||
|
clean = id2go(clean)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_cleaned = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameobject_save(struct gameobject *go, FILE * file)
|
void gameobject_save(struct gameobject *go, FILE * file)
|
||||||
|
@ -330,17 +350,19 @@ void object_gui(struct gameobject *go)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void body_draw_shapes_dbg(cpBody *body, cpShape *shape, void *data) {
|
||||||
|
struct phys2d_shape *s = cpShapeGetUserData(shape);
|
||||||
|
s->debugdraw(s->data);
|
||||||
|
}
|
||||||
|
|
||||||
void gameobject_draw_debugs() {
|
void gameobject_draw_debugs() {
|
||||||
/*
|
|
||||||
YughInfo("DRAWING DEBUG");
|
|
||||||
for (int i = 0; i < arrlen(gameobjects); i++) {
|
for (int i = 0; i < arrlen(gameobjects); i++) {
|
||||||
YughInfo("Drawing this many ... %d", arrlen(gameobjects[i].components));
|
if (!gameobjects[i].body) continue;
|
||||||
for (int j = 0; j < arrlen(gameobjects[i].components); j++) {
|
|
||||||
struct component *c = &gameobjects[i].components[j];
|
cpBodyEachShape(gameobjects[i].body, body_draw_shapes_dbg, NULL);
|
||||||
comp_draw_debug(c);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,8 @@ struct editor {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gameobject {
|
struct gameobject {
|
||||||
union {
|
|
||||||
cpBodyType bodytype;
|
cpBodyType bodytype;
|
||||||
struct gameobject *next;
|
int next;
|
||||||
};
|
|
||||||
float scale;
|
float scale;
|
||||||
float mass;
|
float mass;
|
||||||
float f; /* friction */
|
float f; /* friction */
|
||||||
|
@ -44,6 +42,7 @@ extern struct gameobject *gameobjects;
|
||||||
int MakeGameobject();
|
int MakeGameobject();
|
||||||
void gameobject_apply(struct gameobject *go);
|
void gameobject_apply(struct gameobject *go);
|
||||||
void gameobject_delete(int id);
|
void gameobject_delete(int id);
|
||||||
|
void gameobjects_cleanup();
|
||||||
void toggleprefab(struct gameobject *go);
|
void toggleprefab(struct gameobject *go);
|
||||||
|
|
||||||
struct gameobject *get_gameobject_from_id(int id);
|
struct gameobject *get_gameobject_from_id(int id);
|
||||||
|
|
|
@ -23,7 +23,15 @@ static void **pawns = NULL;
|
||||||
|
|
||||||
void set_pawn(void *pawn) {
|
void set_pawn(void *pawn) {
|
||||||
arrput(pawns, pawn);
|
arrput(pawns, pawn);
|
||||||
YughInfo("Now controling %d pawns.", arrlen(pawns));
|
}
|
||||||
|
|
||||||
|
void remove_pawn(void *pawn) {
|
||||||
|
for (int i = 0; i < arrlen(pawns); i++) {
|
||||||
|
if (pawns[i] == pawn) {
|
||||||
|
pawns[i] = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos)
|
static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos)
|
||||||
|
@ -48,9 +56,14 @@ void input_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_input_signal(char *signal) {
|
void call_input_signal(char *signal) {
|
||||||
for (int i = 0; i < arrlen(pawns); i++)
|
for (int i = arrlen(pawns)-1; i >= 0; i--) {
|
||||||
|
if (pawns[i] == NULL) arrdel(pawns, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < arrlen(pawns); i++) {
|
||||||
script_eval_w_env(signal, pawns[i]);
|
script_eval_w_env(signal, pawns[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *keyname_extd(int key, int scancode) {
|
const char *keyname_extd(int key, int scancode) {
|
||||||
char keybuf[50];
|
char keybuf[50];
|
||||||
|
|
|
@ -31,5 +31,6 @@ struct inputaction
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_pawn(void *pawn);
|
void set_pawn(void *pawn);
|
||||||
|
void remove_pawn(void *pawn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,41 +14,43 @@
|
||||||
|
|
||||||
struct TextureOptions TEX_SPRITE = { 1, 0, 0 };
|
struct TextureOptions TEX_SPRITE = { 1, 0, 0 };
|
||||||
|
|
||||||
struct sprite *sprites;
|
static struct sprite *sprites;
|
||||||
struct sprite *first;
|
static int first = -1;
|
||||||
|
|
||||||
static uint32_t VBO;
|
static uint32_t VBO;
|
||||||
|
|
||||||
int make_sprite(int go)
|
int make_sprite(int go)
|
||||||
{
|
{
|
||||||
YughInfo("Making sprite with gameobject %d", go);
|
|
||||||
|
|
||||||
struct sprite sprite = {
|
struct sprite sprite = {
|
||||||
.color = {1.f, 1.f, 1.f},
|
.color = {1.f, 1.f, 1.f},
|
||||||
.size = {1.f, 1.f},
|
.size = {1.f, 1.f},
|
||||||
.tex = texture_loadfromfile("ph.png"),
|
.tex = texture_loadfromfile("ph.png"),
|
||||||
.go = go,
|
.go = go,
|
||||||
.next = NULL };
|
.next = -1 };
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!first) {
|
if (first<0) {
|
||||||
YughInfo("Making a brand new sprite.");
|
|
||||||
arrput(sprites, sprite);
|
arrput(sprites, sprite);
|
||||||
arrlast(sprites).id = arrlen(sprites)-1;
|
arrlast(sprites).id = arrlen(sprites)-1;
|
||||||
return arrlen(sprites)-1;
|
return arrlen(sprites)-1;
|
||||||
} else {
|
} else {
|
||||||
YughInfo("Reusing a sprite slot.");
|
int slot = first;
|
||||||
int slot = first->id;
|
first = id2sprite(first)->next;
|
||||||
struct sprite *next = first->next;
|
*id2sprite(slot) = sprite;
|
||||||
*first = sprite;
|
|
||||||
first->id = slot;
|
|
||||||
first = next;
|
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sprite_delete(int id)
|
||||||
|
{
|
||||||
|
struct sprite *sp = id2sprite(id);
|
||||||
|
sp->go = -1;
|
||||||
|
sp->next = first;
|
||||||
|
first = id;
|
||||||
|
}
|
||||||
|
|
||||||
struct sprite *id2sprite(int id) {
|
struct sprite *id2sprite(int id) {
|
||||||
return &sprites[id];
|
return &sprites[id];
|
||||||
}
|
}
|
||||||
|
@ -72,13 +74,7 @@ void sprite_io(struct sprite *sprite, FILE *f, int read)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprite_delete(int id)
|
|
||||||
{
|
|
||||||
struct sprite *sp = id2sprite(id);
|
|
||||||
sp->go = -1;
|
|
||||||
sp->next = first;
|
|
||||||
first = sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sprite_draw_all()
|
void sprite_draw_all()
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct sprite {
|
||||||
int id;
|
int id;
|
||||||
struct TexAnimation anim;
|
struct TexAnimation anim;
|
||||||
struct Texture *tex;
|
struct Texture *tex;
|
||||||
struct sprite *next;
|
int next;
|
||||||
};
|
};
|
||||||
|
|
||||||
int make_sprite(int go);
|
int make_sprite(int go);
|
||||||
|
|
|
@ -199,6 +199,8 @@ int main(int argc, char **args) {
|
||||||
window_renderall();
|
window_renderall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameobjects_cleanup();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue