<commit_before>
#define DRAW_TRIANGLE_TEXELP(TARGET, X, Y) (&((DRAW_TRIANGLE_TEXEL_TYPE *) TARGET->pixels)[(Y) * TARGET->width + (X)])

#ifndef DRAW_TRIANGLE_COLOR_TO_TEXEL
  #define DRAW_TRIANGLE_COLOR_TO_TEXEL(V) (V)
#endif

#ifndef DRAW_TRIANGLE_TEXEL_TO_COLOR
  #define DRAW_TRIANGLE_TEXEL_TO_COLOR(V) (V)
#endif

#if DRAW_TRIANGLE_BLEND
  #define DRAW_TRIANGLE_DO_BLEND(CTX, SRC, DST) DRAW_TRIANGLE_TEXEL_TO_COLOR(ctx->blend_func(SRC, DRAW_TRIANGLE_COLOR_TO_TEXEL(DST)))
#else
  #define DRAW_TRIANGLE_DO_BLEND(CTX, SRC, DST) DRAW_TRIANGLE_TEXEL_TO_COLOR(SRC)
#endif

#if DRAW_TRIANGLE_ZTEST
  #define ZTEST(NEW, OLD) ((NEW > OLD))
  #define ALPHA_TEST(A) (A > 0.5f)
#else
  #define ZTEST(...) (true)
  #define ALPHA_TEST(...) (true)
#endif

static DRAW_TRIANGLE_FUNC(DRAW_TRIANGLE_FUNC_NAME)
{
#define BLOCK_SIZE 8
#define IROUND(v) (to_q8((float) (v)))

  DRAW_TRIANGLE_TARGET_TYPE *target = (DRAW_TRIANGLE_TARGET_TYPE *) ctx->target;

  p0 = p0 * ctx->viewport_mat;
  p1 = p1 * ctx->viewport_mat;
  p2 = p2 * ctx->viewport_mat;

  q8 px[3] = {IROUND(p0.x), IROUND(p1.x), IROUND(p2.x)};
  q8 py[3] = {IROUND(p0.y), IROUND(p1.y), IROUND(p2.y)};

  q8 area = edge_funcq(px[1] - px[0], py[1] - py[0], px[2] - px[1], py[2] - py[1]);

#if DRAW_TRIANGLE_CULL
  if (area <= 0) {
    return;
  }
#endif

  int32_t minx = qint(MIN3(px[0], px[1], px[2]));
  int32_t miny = qint(MIN3(py[0], py[1], py[2]));
  int32_t maxx = qint(MAX3(px[0], px[1], px[2]));
  int32_t maxy = qint(MAX3(py[0], py[1], py[2]));

  int32_t target_width = target->width;
  int32_t target_height = target->height;

  if (maxx < 0 || maxy < 0 ||
      minx >= (target_width) || miny >= (target_height)) {
    return;
  }

  // Clip bounding rect to target rect
  minx = MAX(0, minx);
  miny = MAX(0, miny);
  maxx = MIN(maxx, (target_width - 1));
  maxy = MIN(maxy, (target_height - 1));

  float rarea = 1.0f / to_float(area);

  float z0 = p0.z;
  float dz1 = p1.z - z0;
  float dz2 = p2.z - z0;

  Vec3q w_xinc = {(py[1] - py[2]),
                  (py[2] - py[0]),
                  (py[0] - py[1])}; // * rarea;
  Vec3q w_yinc = {(px[2] - px[1]),
                  (px[0] - px[2]),
                  (px[1] - px[0])}; // * rarea;

  int blkminx = minx & ~(BLOCK_SIZE - 1);
  int blkminy = miny & ~(BLOCK_SIZE - 1);

  // TODO: Handle edge cases or maybe use 2^n sized targets always
  int blkmaxx = (maxx + BLOCK_SIZE) & ~(BLOCK_SIZE - 1);
  if (blkmaxx > target_width) blkmaxx -= BLOCK_SIZE;

  int blkmaxy = (maxy + BLOCK_SIZE) & ~(BLOCK_SIZE - 1);
  if (blkmaxy > target_height) blkmaxy -= BLOCK_SIZE;

  int blkcountx = (blkmaxx - blkminx) / BLOCK_SIZE;
  int blkcounty = (blkmaxy - blkminy) / BLOCK_SIZE;

  Vec3q blk_xinc = w_xinc * to_q8((int32_t) BLOCK_SIZE);
  Vec3q blk_yinc = w_yinc * to_q8((int32_t) BLOCK_SIZE);

  Vec3q c = {(qmul(px[1], py[2]) - qmul(py[1], px[2])),
             (qmul(px[2], py[0]) - qmul(py[2], px[0])),
             (qmul(px[0], py[1]) - qmul(py[0], px[1]))}; // + (Vec3q){1, 1, 1};
  Vec3q basew = c + w_xinc * to_q8(blkminx) + w_yinc * to_q8(blkminy);

  float t1dx = to_float(w_xinc.y) * rarea;
  float t1dy = to_float(w_yinc.y) * rarea;
  float t2dx = to_float(w_xinc.z) * rarea;
  float t2dy = to_float(w_yinc.z) * rarea;

  q8 blockX = 0;
  q8 blockY = 0;
  q8 q_blockcntx = to_q8(blkcountx);
  q8 q_blockcnty = to_q8(blkcounty);

  for (; blockY < q_blockcnty; blockY += Q_ONE) {
    blockX = 0;

    Vec3q blockW[4];
    blockW[1] = basew + blk_yinc * blockY;
    blockW[3] = blockW[1] + blk_yinc;

#define INOUT(w) (((w.x >= 0) << 0) | ((w.y >= 0) << 1) | ((w.z >= 0) << 2))
    int inout[4] = {0, 0, 0, 0};
    inout[1] = INOUT(blockW[1]);
    inout[3] = INOUT(blockW[3]);

    for (; blockX < q_blockcntx; blockX += Q_ONE) {
      blockW[0] = blockW[1];
      blockW[2] = blockW[3];
      blockW[1] = blockW[0] + blk_xinc;
      blockW[3] = blockW[2] + blk_xinc;

      inout[0] = inout[1];
      inout[2] = inout[3];
      inout[1] = INOUT(blockW[1]);
      inout[3] = INOUT(blockW[3]);

      bool allSame = (inout[0] == inout[1]) && (inout[0] == inout[2]) && (inout[0] == inout[3]);
#if DRAW_TRIANGLE_CULL
      bool allInside = allSame && (inout[0] == 7);
#else
      bool allInside = allSame && (inout[0] == 7 || inout[0] == 0);
#endif
      bool allOutside = allSame && !allInside;

      if (allOutside) {
        continue; /* Block is outside of the triangle */
      }

      int bx = qint(blockX) * BLOCK_SIZE;
      int by = qint(blockY) * BLOCK_SIZE;

      int starty = blkminy + by;
      //int endy = starty + BLOCK_SIZE;
      int startx = blkminx + bx;
      //int endx = blkminx + bx + BLOCK_SIZE;

      float t1row = to_float(blockW[0].y) * rarea;
      float t2row = to_float(blockW[0].z) * rarea;

      float zrow = 1 - (z0 + t1row * dz1 + to_float(blockW[0].z) * rarea * dz2);
      float zmaxx = 1 - (z0 + to_float(blockW[1].y) * rarea * dz1 + to_float(blockW[1].z) * rarea * dz2);
      float zmaxy = 1 - (z0 + to_float(blockW[2].y) * rarea * dz1 + to_float(blockW[2].z) * rarea * dz2);
      float zdx = (zmaxx - zrow) / BLOCK_SIZE;
      float zdy = (zmaxy - zrow) / BLOCK_SIZE;

      zval_t *zp_row = &ctx->zbuffer[starty * target_width + startx];
      DRAW_TRIANGLE_TEXEL_TYPE *bufferp_row = DRAW_TRIANGLE_TEXELP(target, startx, starty);

      if (allInside) {
        // Block is fully inside the triangle

        for (int j = 0; j < BLOCK_SIZE; j++) {
          float t1 = t1row;
          float t2 = t2row;
          float z = zrow;

          zval_t *zp = zp_row;
          DRAW_TRIANGLE_TEXEL_TYPE *bufferp = bufferp_row;

          for (int i = 0; i < BLOCK_SIZE; i++) {
            zval_t zvalue = (zval_t) (z * ZBUFFER_MAX);
            if (ZTEST(zvalue, *zp)) {
              #if DRAW_TRIANGLE_FRAG
                Texel color = {};
                if (fragment(ctx, shader_data, startx + i, starty + j, 1 - t1 - t2, t1, t2, &color)) {
                  *bufferp = DRAW_TRIANGLE_DO_BLEND(ctx, color, *bufferp);
                }

                if (ALPHA_TEST(color.a)) {
                  *zp = zvalue;
                }
              #else
                *zp = zvalue;
              #endif
            }

            t1 += t1dx;
            t2 += t2dx;
            z += zdx;
            zp++;
            bufferp++;
          }

          t1row += t1dy;
          t2row += t2dy;
          zrow += zdy;
          zp_row += target_width;
          bufferp_row += target_width;
        }
      } else {
        // Block is partially inside the triangle

        Vec3q wrow = blockW[0];

        for (int j = 0; j < BLOCK_SIZE; j++) {
          Vec3q w = wrow;
          float t1 = t1row;
          float t2 = t2row;
          float z = zrow;

          zval_t *zp = zp_row;
          DRAW_TRIANGLE_TEXEL_TYPE *bufferp = bufferp_row;

#if DRAW_TRIANGLE_CULL
  #define INSIDE_TRIANGLE(w) ((w.x | w.y | w.z) >= 0)
#else
  #define INSIDE_TRIANGLE(w) (((w.x | w.y | w.z) >= 0) || ((w.x < 0.0f) && (w.y < 0.0f) && (w.z < 0.0f)))
#endif

          for (int i = 0; i < BLOCK_SIZE; i++) {
            if (INSIDE_TRIANGLE(w)) {
              zval_t zvalue = (zval_t) (z * ZBUFFER_MAX);
              if (ZTEST(zvalue, *zp)) {
                #if DRAW_TRIANGLE_FRAG
                  Texel color = {};
                  if (fragment(ctx, shader_data, startx + i, starty + j, 1 - t1 - t2, t1, t2, &color)) {
                    *bufferp = DRAW_TRIANGLE_DO_BLEND(ctx, color, *bufferp);
                  }

                  if (ALPHA_TEST(color.a)) {
                    *zp = zvalue;
                  }
                #else
                  *zp = zvalue;
                #endif
              }
            }

            t1 += t1dx;
            t2 += t2dx;
            z += zdx;
            w = w + w_xinc;
            zp++;
            bufferp++;
          }

          t1row += t1dy;
          t2row += t2dy;
          zrow += zdy;
          wrow = wrow + w_yinc;
          zp_row += target_width;
          bufferp_row += target_width;
        }
      }
    }
  }

#undef INSIDE_TRIANGLE
#undef INOUT
#undef IROUND
#undef BLOCK_SIZE
}

#undef ALPHA_TEST
#undef ZTEST

#undef DRAW_TRIANGLE_DO_BLEND
#undef DRAW_TRIANGLE_TEXELP

#undef DRAW_TRIANGLE_FUNC_NAME
#undef DRAW_TRIANGLE_TARGET_TYPE
#undef DRAW_TRIANGLE_TEXEL_TYPE

#undef DRAW_TRIANGLE_COLOR_TO_TEXEL
#undef DRAW_TRIANGLE_TEXEL_TO_COLOR

#undef DRAW_TRIANGLE_BLEND
#undef DRAW_TRIANGLE_CULL
#undef DRAW_TRIANGLE_FRAG
#undef DRAW_TRIANGLE_ZTEST
<commit_msg>Implement top-left fill rule (fixes "holes" in rectangles)<commit_after>
#define DRAW_TRIANGLE_TEXELP(TARGET, X, Y) (&((DRAW_TRIANGLE_TEXEL_TYPE *) TARGET->pixels)[(Y) * TARGET->width + (X)])

#ifndef DRAW_TRIANGLE_COLOR_TO_TEXEL
  #define DRAW_TRIANGLE_COLOR_TO_TEXEL(V) (V)
#endif

#ifndef DRAW_TRIANGLE_TEXEL_TO_COLOR
  #define DRAW_TRIANGLE_TEXEL_TO_COLOR(V) (V)
#endif

#if DRAW_TRIANGLE_BLEND
  #define DRAW_TRIANGLE_DO_BLEND(CTX, SRC, DST) DRAW_TRIANGLE_TEXEL_TO_COLOR(ctx->blend_func(SRC, DRAW_TRIANGLE_COLOR_TO_TEXEL(DST)))
#else
  #define DRAW_TRIANGLE_DO_BLEND(CTX, SRC, DST) DRAW_TRIANGLE_TEXEL_TO_COLOR(SRC)
#endif

#if DRAW_TRIANGLE_ZTEST
  #define ZTEST(NEW, OLD) ((NEW > OLD))
  #define ALPHA_TEST(A) (A > 0.5f)
#else
  #define ZTEST(...) (true)
  #define ALPHA_TEST(...) (true)
#endif

static DRAW_TRIANGLE_FUNC(DRAW_TRIANGLE_FUNC_NAME)
{
#define BLOCK_SIZE 8
#define IROUND(v) (to_q8((float) (v)))

  DRAW_TRIANGLE_TARGET_TYPE *target = (DRAW_TRIANGLE_TARGET_TYPE *) ctx->target;

  p0 = p0 * ctx->viewport_mat;
  p1 = p1 * ctx->viewport_mat;
  p2 = p2 * ctx->viewport_mat;

  q8 px[3] = {IROUND(p0.x), IROUND(p1.x), IROUND(p2.x)};
  q8 py[3] = {IROUND(p0.y), IROUND(p1.y), IROUND(p2.y)};

  q8 area = edge_funcq(px[1] - px[0], py[1] - py[0], px[2] - px[1], py[2] - py[1]);

#if DRAW_TRIANGLE_CULL
  if (area <= 0) {
    return;
  }
#endif

  int32_t minx = qint(MIN3(px[0], px[1], px[2]));
  int32_t miny = qint(MIN3(py[0], py[1], py[2]));
  int32_t maxx = qint(MAX3(px[0], px[1], px[2]));
  int32_t maxy = qint(MAX3(py[0], py[1], py[2]));

  int32_t target_width = target->width;
  int32_t target_height = target->height;

  if (maxx < 0 || maxy < 0 ||
      minx >= (target_width) || miny >= (target_height)) {
    return;
  }

  // Clip bounding rect to target rect
  minx = MAX(0, minx);
  miny = MAX(0, miny);
  maxx = MIN(maxx, (target_width - 1));
  maxy = MIN(maxy, (target_height - 1));

  float rarea = 1.0f / to_float(area);

  float z0 = p0.z;
  float dz1 = p1.z - z0;
  float dz2 = p2.z - z0;

  Vec3q w_xinc = {(py[1] - py[2]),
                  (py[2] - py[0]),
                  (py[0] - py[1])}; // * rarea;
  Vec3q w_yinc = {(px[2] - px[1]),
                  (px[0] - px[2]),
                  (px[1] - px[0])}; // * rarea;

  int blkminx = minx & ~(BLOCK_SIZE - 1);
  int blkminy = miny & ~(BLOCK_SIZE - 1);

  // TODO: Handle edge cases or maybe use 2^n sized targets always
  int blkmaxx = (maxx + BLOCK_SIZE) & ~(BLOCK_SIZE - 1);
  if (blkmaxx > target_width) blkmaxx -= BLOCK_SIZE;

  int blkmaxy = (maxy + BLOCK_SIZE) & ~(BLOCK_SIZE - 1);
  if (blkmaxy > target_height) blkmaxy -= BLOCK_SIZE;

  int blkcountx = (blkmaxx - blkminx) / BLOCK_SIZE;
  int blkcounty = (blkmaxy - blkminy) / BLOCK_SIZE;

  Vec3q blk_xinc = w_xinc * to_q8((int32_t) BLOCK_SIZE);
  Vec3q blk_yinc = w_yinc * to_q8((int32_t) BLOCK_SIZE);

  Vec3q c = {(qmul(px[1], py[2]) - qmul(py[1], px[2])),
             (qmul(px[2], py[0]) - qmul(py[2], px[0])),
             (qmul(px[0], py[1]) - qmul(py[0], px[1]))}; // + (Vec3q){1, 1, 1};

#define TOPLEFT(a, b) (((b.y == a.y) && (b.x < a.x)) || (b.y < a.y))
  if (!TOPLEFT(p1, p2)) { c.x -= 1; };
  if (!TOPLEFT(p2, p0)) { c.y -= 1; };
  if (!TOPLEFT(p0, p1)) { c.z -= 1; };

  Vec3q basew = c + w_xinc * to_q8(blkminx) + w_yinc * to_q8(blkminy);

  float t1dx = to_float(w_xinc.y) * rarea;
  float t1dy = to_float(w_yinc.y) * rarea;
  float t2dx = to_float(w_xinc.z) * rarea;
  float t2dy = to_float(w_yinc.z) * rarea;

  q8 blockX = 0;
  q8 blockY = 0;
  q8 q_blockcntx = to_q8(blkcountx);
  q8 q_blockcnty = to_q8(blkcounty);

  for (; blockY < q_blockcnty; blockY += Q_ONE) {
    blockX = 0;

    Vec3q blockW[4];
    blockW[1] = basew + blk_yinc * blockY;
    blockW[3] = blockW[1] + blk_yinc;

#define INOUT(w) (((w.x >= 0) << 0) | ((w.y >= 0) << 1) | ((w.z >= 0) << 2))
    int inout[4] = {0, 0, 0, 0};
    inout[1] = INOUT(blockW[1]);
    inout[3] = INOUT(blockW[3]);

    for (; blockX < q_blockcntx; blockX += Q_ONE) {
      blockW[0] = blockW[1];
      blockW[2] = blockW[3];
      blockW[1] = blockW[0] + blk_xinc;
      blockW[3] = blockW[2] + blk_xinc;

      inout[0] = inout[1];
      inout[2] = inout[3];
      inout[1] = INOUT(blockW[1]);
      inout[3] = INOUT(blockW[3]);

      bool allSame = (inout[0] == inout[1]) && (inout[0] == inout[2]) && (inout[0] == inout[3]);
#if DRAW_TRIANGLE_CULL
      bool allInside = allSame && (inout[0] == 7);
#else
      bool allInside = allSame && (inout[0] == 7 || inout[0] == 0);
#endif
      bool allOutside = allSame && !allInside;

      if (allOutside) {
        continue; /* Block is outside of the triangle */
      }

      int bx = qint(blockX) * BLOCK_SIZE;
      int by = qint(blockY) * BLOCK_SIZE;

      int starty = blkminy + by;
      //int endy = starty + BLOCK_SIZE;
      int startx = blkminx + bx;
      //int endx = blkminx + bx + BLOCK_SIZE;

      float t1row = to_float(blockW[0].y) * rarea;
      float t2row = to_float(blockW[0].z) * rarea;

      float zrow = 1 - (z0 + t1row * dz1 + to_float(blockW[0].z) * rarea * dz2);
      float zmaxx = 1 - (z0 + to_float(blockW[1].y) * rarea * dz1 + to_float(blockW[1].z) * rarea * dz2);
      float zmaxy = 1 - (z0 + to_float(blockW[2].y) * rarea * dz1 + to_float(blockW[2].z) * rarea * dz2);
      float zdx = (zmaxx - zrow) / BLOCK_SIZE;
      float zdy = (zmaxy - zrow) / BLOCK_SIZE;

      zval_t *zp_row = &ctx->zbuffer[starty * target_width + startx];
      DRAW_TRIANGLE_TEXEL_TYPE *bufferp_row = DRAW_TRIANGLE_TEXELP(target, startx, starty);

      if (allInside) {
        // Block is fully inside the triangle

        for (int j = 0; j < BLOCK_SIZE; j++) {
          float t1 = t1row;
          float t2 = t2row;
          float z = zrow;

          zval_t *zp = zp_row;
          DRAW_TRIANGLE_TEXEL_TYPE *bufferp = bufferp_row;

          for (int i = 0; i < BLOCK_SIZE; i++) {
            zval_t zvalue = (zval_t) (z * ZBUFFER_MAX);
            if (ZTEST(zvalue, *zp)) {
              #if DRAW_TRIANGLE_FRAG
                Texel color = {};
                if (fragment(ctx, shader_data, startx + i, starty + j, 1 - t1 - t2, t1, t2, &color)) {
                  *bufferp = DRAW_TRIANGLE_DO_BLEND(ctx, color, *bufferp);
                }

                if (ALPHA_TEST(color.a)) {
                  *zp = zvalue;
                }
              #else
                *zp = zvalue;
              #endif
            }

            t1 += t1dx;
            t2 += t2dx;
            z += zdx;
            zp++;
            bufferp++;
          }

          t1row += t1dy;
          t2row += t2dy;
          zrow += zdy;
          zp_row += target_width;
          bufferp_row += target_width;
        }
      } else {
        // Block is partially inside the triangle

        Vec3q wrow = blockW[0];

        for (int j = 0; j < BLOCK_SIZE; j++) {
          Vec3q w = wrow;
          float t1 = t1row;
          float t2 = t2row;
          float z = zrow;

          zval_t *zp = zp_row;
          DRAW_TRIANGLE_TEXEL_TYPE *bufferp = bufferp_row;

#if DRAW_TRIANGLE_CULL
  #define INSIDE_TRIANGLE(w) ((w.x | w.y | w.z) >= 0)
#else
  #define INSIDE_TRIANGLE(w) (((w.x | w.y | w.z) >= 0) || ((w.x < 0.0f) && (w.y < 0.0f) && (w.z < 0.0f)))
#endif

          for (int i = 0; i < BLOCK_SIZE; i++) {
            if (INSIDE_TRIANGLE(w)) {
              zval_t zvalue = (zval_t) (z * ZBUFFER_MAX);
              if (ZTEST(zvalue, *zp)) {
                #if DRAW_TRIANGLE_FRAG
                  Texel color = {};
                  if (fragment(ctx, shader_data, startx + i, starty + j, 1 - t1 - t2, t1, t2, &color)) {
                    *bufferp = DRAW_TRIANGLE_DO_BLEND(ctx, color, *bufferp);
                  }

                  if (ALPHA_TEST(color.a)) {
                    *zp = zvalue;
                  }
                #else
                  *zp = zvalue;
                #endif
              }
            }

            t1 += t1dx;
            t2 += t2dx;
            z += zdx;
            w = w + w_xinc;
            zp++;
            bufferp++;
          }

          t1row += t1dy;
          t2row += t2dy;
          zrow += zdy;
          wrow = wrow + w_yinc;
          zp_row += target_width;
          bufferp_row += target_width;
        }
      }
    }
  }

#undef INSIDE_TRIANGLE
#undef INOUT
#undef IROUND
#undef BLOCK_SIZE
}

#undef ALPHA_TEST
#undef ZTEST

#undef DRAW_TRIANGLE_DO_BLEND
#undef DRAW_TRIANGLE_TEXELP

#undef DRAW_TRIANGLE_FUNC_NAME
#undef DRAW_TRIANGLE_TARGET_TYPE
#undef DRAW_TRIANGLE_TEXEL_TYPE

#undef DRAW_TRIANGLE_COLOR_TO_TEXEL
#undef DRAW_TRIANGLE_TEXEL_TO_COLOR

#undef DRAW_TRIANGLE_BLEND
#undef DRAW_TRIANGLE_CULL
#undef DRAW_TRIANGLE_FRAG
#undef DRAW_TRIANGLE_ZTEST
<|endoftext|>


<commit_before>#include "thriftlink_client.h"

boost::shared_ptr<TTransport> _socket;
boost::shared_ptr<TTransport> _transport;
boost::shared_ptr<TProtocol> _protocol;
boost::shared_ptr<ApiForwardClient> _api;

static bool connect_internal();

bool thrift_connect(const char* ipaddr, int port) {
    boost::shared_ptr<TTransport> socket(new TSocket(ipaddr, port));
    boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    boost::shared_ptr<ApiForwardClient> api(new ApiForwardClient(protocol));

    _socket = socket;
    _transport = transport;
    _protocol = protocol;
    _api = api;

    return connect_internal();
}

void thrift_close() {

    try {
        if (_transport.get() != NULL) {
            _transport->close();
        }
    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return;
    }

    return;
}

static bool connect_internal() {
    try {
        if (_transport.get()!=NULL) {
            if (!_transport->isOpen()) {
                _transport->open();
            }
        }
    } catch (TTransportException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;

    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;
    }

    return true;
}

bool ensure_connection() {
    if (_transport.get() == NULL) return false;
    try{
        if (!_transport->isOpen()) {
            return connect_internal();
        }
    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;
    }

    return true;
}<commit_msg>Update connect_internal() function<commit_after>#include "thriftlink_client.h"

boost::shared_ptr<TTransport> _socket;
boost::shared_ptr<TTransport> _transport;
boost::shared_ptr<TProtocol> _protocol;
boost::shared_ptr<ApiForwardClient> _api;

static bool connect_internal();

bool thrift_connect(const char* ipaddr, int port) {
    boost::shared_ptr<TTransport> socket(new TSocket(ipaddr, port));
    boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    boost::shared_ptr<ApiForwardClient> api(new ApiForwardClient(protocol));

    _socket = socket;
    _transport = transport;
    _protocol = protocol;
    _api = api;

    return connect_internal();
}

void thrift_close() {

    try {
        if (_transport.get() != NULL) {
            _transport->close();
        }
    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return;
    }

    return;
}

static bool connect_internal() {
    try {
        if (_transport.get()!=NULL) {
            if (!_transport->isOpen() || !_socket->isOpen()) {
                _transport->open();
            }
        }
        else {
            return false;
        }
    } catch (TTransportException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;

    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;
    }

    return _transport->isOpen();
}

bool ensure_connection() {
    if (_transport.get() == NULL) return false;
    try{
        if (!_transport->isOpen() || !_socket->isOpen()) {
            return connect_internal();
        }
    } catch (TException& tx) {
        cout << "ERROR: " << tx.what() << endl;
        return false;
    }

    return true;
}<|endoftext|>


<commit_before>// Copyright (C) 2010 Tim Moore (timoore33@gmail.com)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//

#include "ConditionNode.hxx"

namespace simgear
{
using namespace osg;

ConditionNode::ConditionNode()
{
}

ConditionNode::ConditionNode(const ConditionNode& rhs, const CopyOp& op)
    : Group(rhs, op), _condition(rhs._condition)
{
}

ConditionNode::~ConditionNode()
{
}

void ConditionNode::traverse(NodeVisitor& nv)
{
    if (nv.getTraversalMode() == NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {
        unsigned numChildren = getNumChildren();
        if (numChildren == 0)
            return;
        if (!_condition || _condition->test())
            getChild(0)->accept(nv);
        else if (numChildren > 1)
            getChild(1)->accept(nv);
        else
            return;
    } else {
        Group::traverse(nv);
    }
}

}
<commit_msg>add SGMath.hxx header file to ConditionNode.cxx<commit_after>// Copyright (C) 2010 Tim Moore (timoore33@gmail.com)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//

#include "ConditionNode.hxx"

#include <simgear/math/SGMath.hxx>

namespace simgear
{
using namespace osg;

ConditionNode::ConditionNode()
{
}

ConditionNode::ConditionNode(const ConditionNode& rhs, const CopyOp& op)
    : Group(rhs, op), _condition(rhs._condition)
{
}

ConditionNode::~ConditionNode()
{
}

void ConditionNode::traverse(NodeVisitor& nv)
{
    if (nv.getTraversalMode() == NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {
        unsigned numChildren = getNumChildren();
        if (numChildren == 0)
            return;
        if (!_condition || _condition->test())
            getChild(0)->accept(nv);
        else if (numChildren > 1)
            getChild(1)->accept(nv);
        else
            return;
    } else {
        Group::traverse(nv);
    }
}

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2010, The Mineserver Project
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the The Mineserver Project nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <deque>
#include <fstream>
#include <vector>
#include <ctime>
#include <math.h>
#ifdef WIN32
  #include <winsock2.h>
#endif

#include "logger.h"
#include "constants.h"

#include "tools.h"
#include "map.h"
#include "user.h"
#include "chat.h"
#include "config.h"
#include "physics.h"

namespace
{

void reportError(User *user, std::string message)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "Error!" + COLOR_RED + message, Chat::USER);
}

void playerList(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendUserlist(user);
}

void about(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + Conf::get().sValue("servername") +
                            "Running Mineserver v." + VERSION, Chat::USER);
}

void rules(User *user, std::string command, std::deque<std::string> args)
{
  User *tUser = user;
  if (!args.empty() && user->admin)
    tUser = getUserByNick(args[0]);
  if (tUser != NULL)
  {
    // Send rules
    std::ifstream motdfs( RULESFILE.c_str() );
    std::string temp;

    while (getline(motdfs, temp))
    {
      // If not a comment
      if (temp.empty() || temp[0] == COMMENTPREFIX)
        Chat::get().sendMsg(tUser, temp, Chat::USER);
    }
    motdfs.close();
  }
  else
  {
    reportError(user, "User " + args[0] + " not found (see /players)");
  }
}

void home(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "Teleporting you home!", Chat::USER);
  user->teleport(Map::get().spawnPos.x, Map::get().spawnPos.y + 2, Map::get().spawnPos.z);
}

void kit(User *user, std::string command, std::deque<std::string> args)
{
  if (!args.empty())
  {
    if (args[0] == "starter")
    {
      std::vector<int> kitItems = Conf::get().vValue("kit_starter");
      for (std::vector<int>::iterator iter = kitItems.begin(), end = kitItems.end();
                                      iter != end;
                                      ++iter)
      {
        spawnedItem item;
        item.EID = generateEID();
        item.item = *iter;
        item.count = 1;
        item.x = static_cast<int>(user->pos.x*32 + (rand() % 30));
        item.y = static_cast<int>(user->pos.y*32);
        item.z = static_cast<int>(user->pos.z*32 + (rand() % 30));
        Map::get().sendPickupSpawn(item);
        kitItems.pop_back();
      }
    }
  }
}

void saveMap(User *user, std::string command, std::deque<std::string> args)
{
  Map::get().saveWholeMap();
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "SERVER:" + COLOR_RED + " Saved map to disc",
                      Chat::USER);
}

void kick(User *user, std::string command, std::deque<std::string> args)
{
  if (!args.empty())
  {
    std::string victim = args[0];
    LOG("Kicking: " + victim);

    User *tUser = getUserByNick(victim);

    if (tUser != NULL)
    {
      args.pop_front();
      std::string kickMsg;
      if (args.empty())
      {
        kickMsg = Conf::get().sValue("default_kick_message");
      }
      else
      {
        while (!args.empty())
        {
          kickMsg += args[0] + " ";
          args.pop_front();
        }
      }

      tUser->kick(kickMsg);
      LOG("Kicked!");
    }
    else
    {
      reportError(user, "User " + victim + " not found (see /players)");
    }
  }
  else
  {
    reportError(user, "Usage: /kick user [reason]");
  }
}

void coordinateTeleport(User *user, std::string command, std::deque<std::string> args)
{
  if (args.size() > 2)
  {
    LOG(user->nick + " teleport to: " + args[0] + " " + args[1] + " " + args[2]);
    double x = atof(args[0].c_str());
    double y = atof(args[1].c_str());
    double z = atof(args[2].c_str());
    user->teleport(x, y, z);
  }
}

void userTeleport(User *user, std::string command, std::deque<std::string> args)
{
  if (args.size() == 1)
  {
    LOG(user->nick + " teleport to: " + args[0]);
    User *tUser = getUserByNick(args[0]);
    if (tUser != NULL)
      user->teleport(tUser->pos.x, tUser->pos.y + 2, tUser->pos.z);
    else
      reportError(user, "User " + args[0] + " not found (see /players)");
  }
  else if (args.size() == 2)
  {
    LOG(user->nick + ": teleport " + args[0] + " to " + args[1]);

    User *whatUser = getUserByNick(args[0]);
    User *toUser   = getUserByNick(args[1]);

    if (whatUser != NULL && toUser != NULL)
    {
      whatUser->teleport(toUser->pos.x, toUser->pos.y + 2, toUser->pos.z);
      Chat::get().sendMsg(user, COLOR_MAGENTA + "Teleported!", Chat::USER);
    }
    else
    {
      reportError(user, "User " + (whatUser == NULL ? args[0] : args[1]) +
                        " not found (see /players");
    }
  }
}

void reloadConfiguration(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().loadAdmins(ADMINFILE);
  Conf::get().load(CONFIGFILE);

  // Set physics enable state based on config
  Physics::get().enabled = ((Conf::get().iValue("liquid_physics")==0)?false:true);

  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "SERVER:" + COLOR_RED +
                            " Reloaded admins and config", Chat::USER);

  // Note that the MOTD is loaded on-demand each time it is requested
}

bool isValidItem(int id)
{
  if (id < 1) // zero or negative items are all invalid
    return false;
  if (id > 91 && id < 256) // these are undefined blocks and items
    return false;
  if (id == 2256 || id == 2257) // records are special cased
    return true;
  if (id > 350) // high items are invalid
    return false;
  if (id >= BLOCK_RED_CLOTH && id <= BLOCK_GRAY_CLOTH) // coloured cloth causes client crashes
    return false;
  return true;
}

int roundUpTo(int x, int nearest)
{
  x += (nearest - 1);
  x /= nearest;
  x *= nearest;
  return x;
}

void giveItems(User *user, std::string command, std::deque<std::string> args)
{
  User *tUser = NULL;
  int itemId = 0, itemCount, itemStacks;

  if (args.size() > 1)
  {
    tUser = getUserByNick(args[0]);

    itemId = Conf::get().iValue(args[1]);

    if (itemId == 0)
      itemId = atoi(args[1].c_str());

    // Check item validity
    if (!isValidItem(itemId))
      return;

    if (args.size() > 2)
      itemCount = atoi(args[2].c_str());
    else
      itemCount = 0;

    itemStacks = roundUpTo(itemCount, 64) / 64;
    itemCount  = itemCount % 64;
  }
  else
  {
    reportError(user, "Too few parameters.");
  }

  if (tUser)
  {
    int amount = 64;
    for (int i = 0; i < itemStacks; i++)
    {
      // if last stack
      if (i == itemStacks - 1)
        amount = itemCount;

      spawnedItem item;
      item.EID = generateEID();
      item.item = itemId;
      item.health = 0;
      item.count = amount;
      item.x = static_cast<int>(tUser->pos.x * 32);
      item.y = static_cast<int>(tUser->pos.y * 32);
      item.z = static_cast<int>(tUser->pos.z * 32);

      Map::get().sendPickupSpawn(item);
    }

    Chat::get().sendMsg(user, COLOR_RED + user->nick + " spawned items", Chat::ADMINS);
  }
  else
  {
    reportError(user, "User " + args[0] + " not found (see /players)");
  }
}

}

void Chat::registerStandardCommands()
{
  registerCommand("players", playerList, false);
  registerCommand("about", about, false);
  registerCommand("rules", rules, false);
  registerCommand("home", home, false);
  registerCommand("kit", kit, false);
  registerCommand("save", saveMap, true);
  registerCommand("kick", kick, true);
  registerCommand("ctp", coordinateTeleport, true);
  registerCommand("tp", userTeleport, true);
  registerCommand("reload", reloadConfiguration, true);
  registerCommand("give", giveItems, true);
}
<commit_msg>Minor change for /give command, first check if the item is a number and then search config.<commit_after>/*
Copyright (c) 2010, The Mineserver Project
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the The Mineserver Project nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <deque>
#include <fstream>
#include <vector>
#include <ctime>
#include <math.h>
#ifdef WIN32
  #include <winsock2.h>
#endif

#include "logger.h"
#include "constants.h"

#include "tools.h"
#include "map.h"
#include "user.h"
#include "chat.h"
#include "config.h"
#include "physics.h"

namespace
{

void reportError(User *user, std::string message)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "Error!" + COLOR_RED + message, Chat::USER);
}

void playerList(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendUserlist(user);
}

void about(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + Conf::get().sValue("servername") +
                            "Running Mineserver v." + VERSION, Chat::USER);
}

void rules(User *user, std::string command, std::deque<std::string> args)
{
  User *tUser = user;
  if (!args.empty() && user->admin)
    tUser = getUserByNick(args[0]);
  if (tUser != NULL)
  {
    // Send rules
    std::ifstream motdfs( RULESFILE.c_str() );
    std::string temp;

    while (getline(motdfs, temp))
    {
      // If not a comment
      if (temp.empty() || temp[0] == COMMENTPREFIX)
        Chat::get().sendMsg(tUser, temp, Chat::USER);
    }
    motdfs.close();
  }
  else
  {
    reportError(user, "User " + args[0] + " not found (see /players)");
  }
}

void home(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "Teleporting you home!", Chat::USER);
  user->teleport(Map::get().spawnPos.x, Map::get().spawnPos.y + 2, Map::get().spawnPos.z);
}

void kit(User *user, std::string command, std::deque<std::string> args)
{
  if (!args.empty())
  {
    if (args[0] == "starter")
    {
      std::vector<int> kitItems = Conf::get().vValue("kit_starter");
      for (std::vector<int>::iterator iter = kitItems.begin(), end = kitItems.end();
                                      iter != end;
                                      ++iter)
      {
        spawnedItem item;
        item.EID = generateEID();
        item.item = *iter;
        item.count = 1;
        item.x = static_cast<int>(user->pos.x*32 + (rand() % 30));
        item.y = static_cast<int>(user->pos.y*32);
        item.z = static_cast<int>(user->pos.z*32 + (rand() % 30));
        Map::get().sendPickupSpawn(item);
        kitItems.pop_back();
      }
    }
  }
}

void saveMap(User *user, std::string command, std::deque<std::string> args)
{
  Map::get().saveWholeMap();
  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "SERVER:" + COLOR_RED + " Saved map to disc",
                      Chat::USER);
}

void kick(User *user, std::string command, std::deque<std::string> args)
{
  if (!args.empty())
  {
    std::string victim = args[0];
    LOG("Kicking: " + victim);

    User *tUser = getUserByNick(victim);

    if (tUser != NULL)
    {
      args.pop_front();
      std::string kickMsg;
      if (args.empty())
      {
        kickMsg = Conf::get().sValue("default_kick_message");
      }
      else
      {
        while (!args.empty())
        {
          kickMsg += args[0] + " ";
          args.pop_front();
        }
      }

      tUser->kick(kickMsg);
      LOG("Kicked!");
    }
    else
    {
      reportError(user, "User " + victim + " not found (see /players)");
    }
  }
  else
  {
    reportError(user, "Usage: /kick user [reason]");
  }
}

void coordinateTeleport(User *user, std::string command, std::deque<std::string> args)
{
  if (args.size() > 2)
  {
    LOG(user->nick + " teleport to: " + args[0] + " " + args[1] + " " + args[2]);
    double x = atof(args[0].c_str());
    double y = atof(args[1].c_str());
    double z = atof(args[2].c_str());
    user->teleport(x, y, z);
  }
}

void userTeleport(User *user, std::string command, std::deque<std::string> args)
{
  if (args.size() == 1)
  {
    LOG(user->nick + " teleport to: " + args[0]);
    User *tUser = getUserByNick(args[0]);
    if (tUser != NULL)
      user->teleport(tUser->pos.x, tUser->pos.y + 2, tUser->pos.z);
    else
      reportError(user, "User " + args[0] + " not found (see /players)");
  }
  else if (args.size() == 2)
  {
    LOG(user->nick + ": teleport " + args[0] + " to " + args[1]);

    User *whatUser = getUserByNick(args[0]);
    User *toUser   = getUserByNick(args[1]);

    if (whatUser != NULL && toUser != NULL)
    {
      whatUser->teleport(toUser->pos.x, toUser->pos.y + 2, toUser->pos.z);
      Chat::get().sendMsg(user, COLOR_MAGENTA + "Teleported!", Chat::USER);
    }
    else
    {
      reportError(user, "User " + (whatUser == NULL ? args[0] : args[1]) +
                        " not found (see /players");
    }
  }
}

void reloadConfiguration(User *user, std::string command, std::deque<std::string> args)
{
  Chat::get().loadAdmins(ADMINFILE);
  Conf::get().load(CONFIGFILE);

  // Set physics enable state based on config
  Physics::get().enabled = ((Conf::get().iValue("liquid_physics")==0)?false:true);

  Chat::get().sendMsg(user, COLOR_DARK_MAGENTA + "SERVER:" + COLOR_RED +
                            " Reloaded admins and config", Chat::USER);

  // Note that the MOTD is loaded on-demand each time it is requested
}

bool isValidItem(int id)
{
  if (id < 1) // zero or negative items are all invalid
    return false;
  if (id > 91 && id < 256) // these are undefined blocks and items
    return false;
  if (id == 2256 || id == 2257) // records are special cased
    return true;
  if (id > 350) // high items are invalid
    return false;
  if (id >= BLOCK_RED_CLOTH && id <= BLOCK_GRAY_CLOTH) // coloured cloth causes client crashes
    return false;
  return true;
}

int roundUpTo(int x, int nearest)
{
  x += (nearest - 1);
  x /= nearest;
  x *= nearest;
  return x;
}

void giveItems(User *user, std::string command, std::deque<std::string> args)
{
  User *tUser = NULL;
  int itemId = 0, itemCount, itemStacks;

  if (args.size() > 1)
  {
    tUser = getUserByNick(args[0]);

    //First check if item is a number
    itemId = atoi(args[1].c_str());

    //If item was not a number, search the name from config
    if (itemId == 0)
      itemId = Conf::get().iValue(args[1]);

    // Check item validity
    if (!isValidItem(itemId))
      return;

    if (args.size() > 2)
      itemCount = atoi(args[2].c_str());
    else
      itemCount = 0;

    itemStacks = roundUpTo(itemCount, 64) / 64;
    itemCount  = itemCount % 64;
  }
  else
  {
    reportError(user, "Too few parameters.");
  }

  if (tUser)
  {
    int amount = 64;
    for (int i = 0; i < itemStacks; i++)
    {
      // if last stack
      if (i == itemStacks - 1)
        amount = itemCount;

      spawnedItem item;
      item.EID = generateEID();
      item.item = itemId;
      item.health = 0;
      item.count = amount;
      item.x = static_cast<int>(tUser->pos.x * 32);
      item.y = static_cast<int>(tUser->pos.y * 32);
      item.z = static_cast<int>(tUser->pos.z * 32);

      Map::get().sendPickupSpawn(item);
    }

    Chat::get().sendMsg(user, COLOR_RED + user->nick + " spawned items", Chat::ADMINS);
  }
  else
  {
    reportError(user, "User " + args[0] + " not found (see /players)");
  }
}

}

void Chat::registerStandardCommands()
{
  registerCommand("players", playerList, false);
  registerCommand("about", about, false);
  registerCommand("rules", rules, false);
  registerCommand("home", home, false);
  registerCommand("kit", kit, false);
  registerCommand("save", saveMap, true);
  registerCommand("kick", kick, true);
  registerCommand("ctp", coordinateTeleport, true);
  registerCommand("tp", userTeleport, true);
  registerCommand("reload", reloadConfiguration, true);
  registerCommand("give", giveItems, true);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "creature.h"
#include "datmanager.h"
#include "localplayer.h"
#include "map.h"
#include <framework/platform/platform.h>
#include <framework/graphics/graphics.h>

Creature::Creature() : Thing(Otc::Creature)
{
    m_healthPercent = 0;
    m_direction = Otc::South;

    m_walking = false;
    m_walkOffsetX = 0;
    m_walkOffsetY = 0;

    m_informationFont = g_fonts.getFont("tibia-12px-rounded");
}

void Creature::draw(int x, int y)
{
    //dump << (int)m_speed;

    // gspeed = 100
    // pspeed = 234
    // (recorded) 400 - 866 = 466
    // (calc by ot eq) 1000 * 100 / 234 = 427

    // gspeed = 150
    // pspeed = 234
    // (recorded) 934 - 1597 = 663
    // (calc by ot eq) 1000 * 150 / 234 = 641

    // gspeed = 100
    // pspeed = 110
    // (recorded) 900 - 1833 = 933
    // (calc by ot eq) 1000 * 100 / 110 = 909

    // 1000 * groundSpeed / playerSpeed

    // TODO 1: FIX RENDER STEP 2
    // TODO 2: FIX DIAGONAL WALKING, BUGS MAP
    // TODO 3: ADD ANIMATION

    x += m_walkOffsetX;
    y += m_walkOffsetY;

    const ThingAttributes& attributes = getAttributes();

    // Render creature
    for(m_yDiv = 0; m_yDiv < attributes.ydiv; m_yDiv++) {

        // continue if we dont have this addon.
        if(m_yDiv > 0 && !(m_outfit.addons & (1 << (m_yDiv-1))))
            continue;

        // draw white item
        internalDraw(x, y, 0);

        // draw mask if exists
        if(attributes.blendframes > 1) {
            // switch to blend color mode
            g_graphics.bindBlendFunc(Fw::BlendColorzing);

            // head
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.head]);
            internalDraw(x, y, 1, Otc::SpriteYellowMask);

            // body
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.body]);
            internalDraw(x, y, 1, Otc::SpriteRedMask);

            // legs
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.legs]);
            internalDraw(x, y, 1, Otc::SpriteGreenMask);

            // feet
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.feet]);
            internalDraw(x, y, 1, Otc::SpriteBlueMask);

            // restore default blend func
            g_graphics.bindBlendFunc(Fw::BlendDefault);
            g_graphics.bindColor(Fw::white);
        }
    }

    // Update animation and position
    if(m_walking && attributes.animcount > 1) {

        if(g_platform.getTicks() - m_lastTicks >= m_walkTimePerPixel) {
            int pixelsWalked = std::floor((g_platform.getTicks() - m_lastTicks) / m_walkTimePerPixel);
            int remainingTime = (g_platform.getTicks() - m_lastTicks) % (int)m_walkTimePerPixel;

            if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
                m_walkOffsetY = std::max(m_walkOffsetY - pixelsWalked, 0);
            else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
                m_walkOffsetY = std::min(m_walkOffsetY + pixelsWalked, 0);

            if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
                m_walkOffsetX = std::min(m_walkOffsetX + pixelsWalked, 0);
            else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
                m_walkOffsetX = std::max(m_walkOffsetX - pixelsWalked, 0);

            //double walkOffset = std::max(m_walkOffsetX, m_walkOffsetY);

            /*if((32 - fabs(walkOffset)) / 8 % 2 == 0) {
                if(m_animation+1 == attributes.animcount)
                    m_animation = 1;
                else
                    m_animation++;

                //m_lastTicks = g_platform.getTicks();
            }*/

            if(((m_walkOffsetX == 0 && m_walkOffsetY == 0) && m_walkOffsetX != m_walkOffsetY) ||
               ((m_walkOffsetX == 0 || m_walkOffsetY == 0) && m_walkOffsetX == m_walkOffsetY)) {
                m_walking = false;
                m_walkOffsetX = 0;
                m_walkOffsetY = 0;
                m_animation = 0;
            }

            m_lastTicks = g_platform.getTicks() - remainingTime;
        }
    }
}

void Creature::drawInformation(int x, int y, bool useGray)
{
    Color fillColor = Color(96, 96, 96);

    if(!useGray)
        fillColor = m_informationColor;

    Rect backgroundRect = Rect(x-(14.5), y, 27, 4);
    Rect healthRect = backgroundRect.expanded(-1);
    healthRect.setWidth((m_healthPercent/100.0)*25);

    g_graphics.bindColor(Fw::black);
    g_graphics.drawFilledRect(backgroundRect);

    g_graphics.bindColor(fillColor);
    g_graphics.drawFilledRect(healthRect);

    // name
    m_informationFont->renderText(m_name, Rect(x-100, y-15, 200, 15), Fw::AlignTopCenter, fillColor);
}

void Creature::walk(const Position& position)
{
    // set walking state
    m_walking = true;
    m_walkOffsetX = 0;
    m_walkOffsetY = 0;
    m_walkingFromPosition = m_position;
    int walkTimeFactor = 1;

    // update map tiles
    g_map.removeThingByPtr(asThing());
    m_position = position;
    g_map.addThing(asThing());

    // set new direction
    if(m_walkingFromPosition + Position(0, -1, 0) == m_position) {
        m_direction = Otc::North;
        m_walkOffsetY = 32;
    }
    else if(m_walkingFromPosition + Position(1, 0, 0) == m_position) {
        m_direction = Otc::East;
        m_walkOffsetX = -32;
    }
    else if(m_walkingFromPosition + Position(0, 1, 0) == m_position) {
        m_direction = Otc::South;
        m_walkOffsetY = -32;
    }
    else if(m_walkingFromPosition + Position(-1, 0, 0) == m_position) {
        m_direction = Otc::West;
        m_walkOffsetX = 32;
    }
    else if(m_walkingFromPosition + Position(1, -1, 0) == m_position) {
        m_direction = Otc::NorthEast;
        m_walkOffsetX = -32;
        m_walkOffsetY = 32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(1, 1, 0) == m_position) {
        m_direction = Otc::SouthEast;
        m_walkOffsetX = -32;
        m_walkOffsetY = -32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(-1, 1, 0) == m_position) {
        m_direction = Otc::SouthWest;
        m_walkOffsetX = 32;
        m_walkOffsetY = -32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(-1, -1, 0) == m_position) {
        m_direction = Otc::NorthWest;
        m_walkOffsetX = 32;
        m_walkOffsetY = 32;
        walkTimeFactor = 2;
    }
    else { // Teleport
        // we teleported, dont walk or change direction
        m_walking = false;
    }

    // Calculate xDiv
    if(m_direction >= 4) {
        if(m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
            m_xDiv = Otc::East;
        else if(m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
            m_xDiv = Otc::West;
    }
    else {
        m_xDiv = m_direction;
    }

    // get walk speed
    int groundSpeed = 0;

    ThingPtr ground = g_map.getThing(m_position, 0);
    if(ground)
        groundSpeed = ground->getAttributes().speed;

    float walkTime = walkTimeFactor * 1000.0 * (float)groundSpeed / m_speed;
    walkTime = walkTime == 0 ? 1000 : walkTime;

    m_walkTimePerPixel = walkTime / 32.0;

    m_lastTicks = g_platform.getTicks();
}

void Creature::setHealthPercent(uint8 healthPercent)
{
    int oldHealthPercent = m_healthPercent;
    m_healthPercent = healthPercent;
    onHealthPercentChange(oldHealthPercent);
}

const ThingAttributes& Creature::getAttributes()
{
    return g_dat.getCreatureAttributes(m_outfit.type);
}

void Creature::onHealthPercentChange(int)
{
    m_informationColor = Fw::black;

    if(m_healthPercent > 92) {
        m_informationColor.setGreen(188);
    }
    else if(m_healthPercent > 60) {
        m_informationColor.setRed(80);
        m_informationColor.setGreen(161);
        m_informationColor.setBlue(80);
    }
    else if(m_healthPercent > 30) {
        m_informationColor.setRed(161);
        m_informationColor.setGreen(161);
    }
    else if(m_healthPercent > 8) {
        m_informationColor.setRed(160);
        m_informationColor.setGreen(39);
        m_informationColor.setBlue(39);
    }
    else if(m_healthPercent > 3) {
        m_informationColor.setRed(160);
    }
    else {
        m_informationColor.setRed(79);
    }
}
<commit_msg>walk animation<commit_after>/*
 * Copyright (c) 2010-2011 OTClient <https://github.com/edubart/otclient>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "creature.h"
#include "datmanager.h"
#include "localplayer.h"
#include "map.h"
#include <framework/platform/platform.h>
#include <framework/graphics/graphics.h>

Creature::Creature() : Thing(Otc::Creature)
{
    m_healthPercent = 0;
    m_direction = Otc::South;

    m_walking = false;
    m_walkOffsetX = 0;
    m_walkOffsetY = 0;

    m_informationFont = g_fonts.getFont("tibia-12px-rounded");
}

void Creature::draw(int x, int y)
{
    //dump << (int)m_speed;

    // gspeed = 100
    // pspeed = 234
    // (recorded) 400 - 866 = 466
    // (calc by ot eq) 1000 * 100 / 234 = 427

    // gspeed = 150
    // pspeed = 234
    // (recorded) 934 - 1597 = 663
    // (calc by ot eq) 1000 * 150 / 234 = 641

    // gspeed = 100
    // pspeed = 110
    // (recorded) 900 - 1833 = 933
    // (calc by ot eq) 1000 * 100 / 110 = 909

    // 1000 * groundSpeed / playerSpeed

    // TODO 1: FIX RENDER STEP 2
    // TODO 2: FIX DIAGONAL WALKING, BUGS MAP
    // TODO 3: ADD ANIMATION

    x += m_walkOffsetX;
    y += m_walkOffsetY;

    const ThingAttributes& attributes = getAttributes();

    // Render creature
    for(m_yDiv = 0; m_yDiv < attributes.ydiv; m_yDiv++) {

        // continue if we dont have this addon.
        if(m_yDiv > 0 && !(m_outfit.addons & (1 << (m_yDiv-1))))
            continue;

        // draw white item
        internalDraw(x, y, 0);

        // draw mask if exists
        if(attributes.blendframes > 1) {
            // switch to blend color mode
            g_graphics.bindBlendFunc(Fw::BlendColorzing);

            // head
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.head]);
            internalDraw(x, y, 1, Otc::SpriteYellowMask);

            // body
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.body]);
            internalDraw(x, y, 1, Otc::SpriteRedMask);

            // legs
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.legs]);
            internalDraw(x, y, 1, Otc::SpriteGreenMask);

            // feet
            g_graphics.bindColor(Otc::OutfitColors[m_outfit.feet]);
            internalDraw(x, y, 1, Otc::SpriteBlueMask);

            // restore default blend func
            g_graphics.bindBlendFunc(Fw::BlendDefault);
            g_graphics.bindColor(Fw::white);
        }
    }

    // Update animation and position
    if(m_walking && attributes.animcount > 1) {

        if(g_platform.getTicks() - m_lastTicks >= m_walkTimePerPixel) {
            int pixelsWalked = std::floor((g_platform.getTicks() - m_lastTicks) / m_walkTimePerPixel);
            int remainingTime = (g_platform.getTicks() - m_lastTicks) % (int)m_walkTimePerPixel;

            if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
                m_walkOffsetY = std::max(m_walkOffsetY - pixelsWalked, 0);
            else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
                m_walkOffsetY = std::min(m_walkOffsetY + pixelsWalked, 0);

            if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
                m_walkOffsetX = std::min(m_walkOffsetX + pixelsWalked, 0);
            else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
                m_walkOffsetX = std::max(m_walkOffsetX - pixelsWalked, 0);

            int walkOffset = std::max(fabs(m_walkOffsetX), fabs(m_walkOffsetY));

            if(walkOffset % 8 == 0) {
                if(m_animation+1 == attributes.animcount)
                    m_animation = 1;
                else
                    m_animation++;
            }

            if(((m_walkOffsetX == 0 && m_walkOffsetY == 0) && m_walkOffsetX != m_walkOffsetY) ||
               ((m_walkOffsetX == 0 || m_walkOffsetY == 0) && m_walkOffsetX == m_walkOffsetY)) {
                m_walking = false;
                m_walkOffsetX = 0;
                m_walkOffsetY = 0;
                m_animation = 0;
            }

            m_lastTicks = g_platform.getTicks() - remainingTime;
        }
    }
}

void Creature::drawInformation(int x, int y, bool useGray)
{
    Color fillColor = Color(96, 96, 96);

    if(!useGray)
        fillColor = m_informationColor;

    Rect backgroundRect = Rect(x-(14.5), y, 27, 4);
    Rect healthRect = backgroundRect.expanded(-1);
    healthRect.setWidth((m_healthPercent/100.0)*25);

    g_graphics.bindColor(Fw::black);
    g_graphics.drawFilledRect(backgroundRect);

    g_graphics.bindColor(fillColor);
    g_graphics.drawFilledRect(healthRect);

    // name
    m_informationFont->renderText(m_name, Rect(x-100, y-15, 200, 15), Fw::AlignTopCenter, fillColor);
}

void Creature::walk(const Position& position)
{
    // set walking state
    m_walking = true;
    m_walkOffsetX = 0;
    m_walkOffsetY = 0;
    m_walkingFromPosition = m_position;
    int walkTimeFactor = 1;

    // update map tiles
    g_map.removeThingByPtr(asThing());
    m_position = position;
    g_map.addThing(asThing());

    // set new direction
    if(m_walkingFromPosition + Position(0, -1, 0) == m_position) {
        m_direction = Otc::North;
        m_walkOffsetY = 32;
    }
    else if(m_walkingFromPosition + Position(1, 0, 0) == m_position) {
        m_direction = Otc::East;
        m_walkOffsetX = -32;
    }
    else if(m_walkingFromPosition + Position(0, 1, 0) == m_position) {
        m_direction = Otc::South;
        m_walkOffsetY = -32;
    }
    else if(m_walkingFromPosition + Position(-1, 0, 0) == m_position) {
        m_direction = Otc::West;
        m_walkOffsetX = 32;
    }
    else if(m_walkingFromPosition + Position(1, -1, 0) == m_position) {
        m_direction = Otc::NorthEast;
        m_walkOffsetX = -32;
        m_walkOffsetY = 32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(1, 1, 0) == m_position) {
        m_direction = Otc::SouthEast;
        m_walkOffsetX = -32;
        m_walkOffsetY = -32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(-1, 1, 0) == m_position) {
        m_direction = Otc::SouthWest;
        m_walkOffsetX = 32;
        m_walkOffsetY = -32;
        walkTimeFactor = 2;
    }
    else if(m_walkingFromPosition + Position(-1, -1, 0) == m_position) {
        m_direction = Otc::NorthWest;
        m_walkOffsetX = 32;
        m_walkOffsetY = 32;
        walkTimeFactor = 2;
    }
    else { // Teleport
        // we teleported, dont walk or change direction
        m_walking = false;
    }

    // Calculate xDiv
    if(m_direction >= 4) {
        if(m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
            m_xDiv = Otc::East;
        else if(m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
            m_xDiv = Otc::West;
    }
    else {
        m_xDiv = m_direction;
    }

    // get walk speed
    int groundSpeed = 0;

    ThingPtr ground = g_map.getThing(m_position, 0);
    if(ground)
        groundSpeed = ground->getAttributes().speed;

    float walkTime = walkTimeFactor * 1000.0 * (float)groundSpeed / m_speed;
    walkTime = walkTime == 0 ? 1000 : walkTime;

    m_walkTimePerPixel = walkTime / 32.0;

    m_lastTicks = g_platform.getTicks();
}

void Creature::setHealthPercent(uint8 healthPercent)
{
    int oldHealthPercent = m_healthPercent;
    m_healthPercent = healthPercent;
    onHealthPercentChange(oldHealthPercent);
}

const ThingAttributes& Creature::getAttributes()
{
    return g_dat.getCreatureAttributes(m_outfit.type);
}

void Creature::onHealthPercentChange(int)
{
    m_informationColor = Fw::black;

    if(m_healthPercent > 92) {
        m_informationColor.setGreen(188);
    }
    else if(m_healthPercent > 60) {
        m_informationColor.setRed(80);
        m_informationColor.setGreen(161);
        m_informationColor.setBlue(80);
    }
    else if(m_healthPercent > 30) {
        m_informationColor.setRed(161);
        m_informationColor.setGreen(161);
    }
    else if(m_healthPercent > 8) {
        m_informationColor.setRed(160);
        m_informationColor.setGreen(39);
        m_informationColor.setBlue(39);
    }
    else if(m_healthPercent > 3) {
        m_informationColor.setRed(160);
    }
    else {
        m_informationColor.setRed(79);
    }
}
<|endoftext|>


<commit_before>/*
* Copyright (c) 2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/

#include <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"

// English localization file
// This is an example translation file without strings in it.

namespace i2p
{
namespace i18n
{
namespace chinese // language namespace
{
	// language name in lowercase
	static std::string language = "chinese";

	// See for language plural forms here:
	// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
	static int plural (int n) {
		return 0;
	}

	static std::map<std::string, std::string> strings
	{
		{"KiB", "KiB"},
		{"MiB", "MiB"},
		{"GiB", "GiB"},
		{"building", "正在构建"},
		{"failed", "连接失败"},
		{"expiring", "即将过期"},
		{"established", "连接建立"},
		{"unknown", "未知"},
		{"exploratory", "探索隧道"},
		{"Purple I2P Webconsole", "Purple I2P 网页控制台"},
		{"i2pd webconsole", "i2pd 网页控制台"},
		{"Main page", "主页"},
		{"Router commands", "路由命令"},
		{"Local Destinations", "本地目标"},
		{"LeaseSets", "租约集"},
		{"Tunnels", "隧道"},
		{"Transit Tunnels", "中转隧道"},
		{"Transports", "传输"},
		{"I2P tunnels", "I2P 隧道"},
		{"SAM sessions", "SAM 会话"},
		{"ERROR", "错误"},
		{"OK", "良好"},
		{"Testing", "测试中"},
		{"Firewalled", "被防火墙阻挡"},
		{"Unknown", "未知"},
		{"Proxy", "代理"},
		{"Mesh", "网格组网"},
		{"Error", "错误"},
		{"Clock skew", "时钟偏移"},
		{"Offline", "离线"},
		{"Symmetric NAT", "对称 NAT"},
		{"Uptime", "在线时间"},
		{"Network status", "IPv4 网络状态"},
		{"Network status v6", "IPv6 网络状态"},
		{"Stopping in", "距停止还有："},
		{"Family", "家族"},
		{"Tunnel creation success rate", "隧道创建成功率"},
		{"Received", "已接收"},
		{"KiB/s", "KiB/s"},
		{"Sent", "已发送"},
		{"Transit", "中转"},
		{"Data path", "数据文件路径"},
		{"Hidden content. Press on text to see.", "隐藏内容 请点击文本查看。"},
		{"Router Ident", "路由器标识"},
		{"Router Family", "路由器家族"},
		{"Router Caps", "路由器分类"},
		{"Version", "版本"},
		{"Our external address", "外部地址"},
		{"supported", "支持"},
		{"Routers", "路由节点"},
		{"Floodfills", "洪泛节点"},
		{"Client Tunnels", "客户端隧道"},
		{"Services", "服务"},
		{"Enabled", "启用"},
		{"Disabled", "禁用"},
		{"Encrypted B33 address", "加密的 B33 地址"},
		{"Address registration line", "地址域名注册"},
		{"Domain", "域名"},
		{"Generate", "生成"},
		{"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意： 结果字符串可以用于注册次级域名(例如：example.i2p)。若想注册次级域名，请使用 i2pd-tools。"},
		{"Address", "地址"},
		{"Type", "类型"},
		{"EncType", "加密类型"},
		{"Inbound tunnels", "入站隧道"},
		{"ms", "毫秒"},
		{"Outbound tunnels", "出站隧道"},
		{"Tags", "标签"},
		{"Incoming", "传入"},
		{"Outgoing", "传出"},
		{"Destination", "目标"},
		{"Amount", "数量"},
		{"Incoming Tags", "传入标签"},
		{"Tags sessions", "标签会话"},
		{"Status", "状态"},
		{"Local Destination", "本地目标"},
		{"Streams", "流"},
		{"Close stream", "断开流"},
		{"I2CP session not found", "未找到 I2CP 会话"},
		{"I2CP is not enabled", "I2CP 未启用"},
		{"Invalid", "无效"},
		{"Store type", "存储类型"},
		{"Expires", "过期时间"},
		{"Non Expired Leases", "未到期的租约"},
		{"Gateway", "网关"},
		{"TunnelID", "隧道 ID"},
		{"EndDate", "结束日期"},
		{"not floodfill", "非洪泛"},
		{"Queue size", "队列大小"},
		{"Run peer test", "运行群体测试"},
		{"Decline transit tunnels", "拒绝中转隧道"},
		{"Accept transit tunnels", "允许中转隧道"},
		{"Cancel graceful shutdown", "取消计划的停止"},
		{"Start graceful shutdown", "待他人断线后停止"},
		{"Force shutdown", "强制停止"},
		{"Reload external CSS styles", "重载外部 CSS 样式"},
		{"Note: any action done here are not persistent and not changes your config files.", "注意： 此处完成的任何操作都不是永久的，不会更改您的配置文件。"},
		{"Logging level", "日志级别"},
		{"Transit tunnels limit", "中转隧道限制"},
		{"Change", "更换"},
		{"Change language", "更换语言"},
		{"no transit tunnels currently built", "目前未构建中转隧道"},
		{"SAM disabled", "SAM 已禁用"},
		{"no sessions currently running", "没有正在运行的会话"},
		{"SAM session not found", "未找到 SAM 会话"},
		{"SAM Session", "SAM 会话"},
		{"Server Tunnels", "服务器隧道"},
		{"Client Forwards", "客户端转发"},
		{"Server Forwards", "服务器转发"},
		{"Unknown page", "未知页面"},
		{"Invalid token", "无效凭证"},
		{"SUCCESS", "成功"},
		{"Stream closed", "流已关闭"},
		{"Stream not found or already was closed", "流未找到或已关闭"},
		{"Destination not found", "找不到目标"},
		{"StreamID can't be null", "StreamID 不能为空"},
		{"Return to destination page", "返回目标页面"},
		{"You will be redirected in 5 seconds", "您将在5秒内被重定向"},
		{"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
		{"Back to commands list", "返回命令列表"},
		{"Register at reg.i2p", "在 reg.i2p 注册域名"},
		{"Description", "描述"},
		{"A bit information about service on domain", "在此域名上运行的服务的一些信息"},
		{"Submit", "提交"},
		{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
		{"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
		{"Such destination is not found", "找不到此目标"},
		{"Unknown command", "未知指令"},
		{"Command accepted", "已接受指令"},
		{"Proxy error", "代理错误"},
		{"Proxy info", "代理信息"},
		{"Proxy error: Host not found", "代理错误：找不到主机"},
		{"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"},
		{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"},
		{"Invalid request", "无效请求"},
		{"Proxy unable to parse your request", "代理无法解析您的请求"},
		{"addresshelper is not supported", "不支持地址助手"},
		{"Host", "主机"},
		{"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"},
		{"Click here to proceed:", "点击此处继续:"},
		{"Continue", "继续"},
		{"Addresshelper found", "找到地址助手"},
		{"already in router's addressbook", "已在路由器的地址簿中"},
		{"Click here to update record:", "点击此处更新地址簿记录"},
		{"invalid request uri", "无效的 URL 请求"},
		{"Can't detect destination host from request", "无法从请求中检测到目标主机"},
		{"Outproxy failure", "出口代理失效"},
		{"bad outproxy settings", "错误的出口代理设置"},
		{"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内，但未启用出口代理"},
		{"unknown outproxy url", "未知的出口代理地址"},
		{"cannot resolve upstream proxy", "无法解析上游代理"},
		{"hostname too long", "主机名过长"},
		{"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
		{"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
		{"CONNECT error", "连接错误"},
		{"Failed to Connect", "连接失败"},
		{"socks proxy error", "socks 代理错误"},
		{"failed to send request to upstream", "向上游发送请求失败"},
		{"No Reply From socks proxy", "没有来自 socks 代理的回复"},
		{"cannot connect", "无法连接"},
		{"http out proxy not implemented", "http 出口代理未实现"},
		{"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
		{"Host is down", "主机已关闭"},
		{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线，请稍后再试。"},
		{"", ""},
	};

	static std::map<std::string, std::vector<std::string>> plurals
	{
		{"days", {"日"}},
		{"hours", {"时"}},
		{"minutes", {"分"}},
		{"seconds", {"秒"}},
		{"", {""}},
	};

	std::shared_ptr<const i2p::i18n::Locale> GetLocale()
	{
		return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
	}

} // language
} // i18n
} // i2p
<commit_msg>change language file comment<commit_after>/*
* Copyright (c) 2022, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/

#include <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"

// Simplified Chinese localization file
// This is an example translation file without strings in it.

namespace i2p
{
namespace i18n
{
namespace chinese // language namespace
{
	// language name in lowercase
	static std::string language = "chinese";

	// See for language plural forms here:
	// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
	static int plural (int n) {
		return 0;
	}

	static std::map<std::string, std::string> strings
	{
		{"KiB", "KiB"},
		{"MiB", "MiB"},
		{"GiB", "GiB"},
		{"building", "正在构建"},
		{"failed", "连接失败"},
		{"expiring", "即将过期"},
		{"established", "连接建立"},
		{"unknown", "未知"},
		{"exploratory", "探索隧道"},
		{"Purple I2P Webconsole", "Purple I2P 网页控制台"},
		{"i2pd webconsole", "i2pd 网页控制台"},
		{"Main page", "主页"},
		{"Router commands", "路由命令"},
		{"Local Destinations", "本地目标"},
		{"LeaseSets", "租约集"},
		{"Tunnels", "隧道"},
		{"Transit Tunnels", "中转隧道"},
		{"Transports", "传输"},
		{"I2P tunnels", "I2P 隧道"},
		{"SAM sessions", "SAM 会话"},
		{"ERROR", "错误"},
		{"OK", "良好"},
		{"Testing", "测试中"},
		{"Firewalled", "被防火墙阻挡"},
		{"Unknown", "未知"},
		{"Proxy", "代理"},
		{"Mesh", "网格组网"},
		{"Error", "错误"},
		{"Clock skew", "时钟偏移"},
		{"Offline", "离线"},
		{"Symmetric NAT", "对称 NAT"},
		{"Uptime", "在线时间"},
		{"Network status", "IPv4 网络状态"},
		{"Network status v6", "IPv6 网络状态"},
		{"Stopping in", "距停止还有："},
		{"Family", "家族"},
		{"Tunnel creation success rate", "隧道创建成功率"},
		{"Received", "已接收"},
		{"KiB/s", "KiB/s"},
		{"Sent", "已发送"},
		{"Transit", "中转"},
		{"Data path", "数据文件路径"},
		{"Hidden content. Press on text to see.", "隐藏内容 请点击文本查看。"},
		{"Router Ident", "路由器标识"},
		{"Router Family", "路由器家族"},
		{"Router Caps", "路由器分类"},
		{"Version", "版本"},
		{"Our external address", "外部地址"},
		{"supported", "支持"},
		{"Routers", "路由节点"},
		{"Floodfills", "洪泛节点"},
		{"Client Tunnels", "客户端隧道"},
		{"Services", "服务"},
		{"Enabled", "启用"},
		{"Disabled", "禁用"},
		{"Encrypted B33 address", "加密的 B33 地址"},
		{"Address registration line", "地址域名注册"},
		{"Domain", "域名"},
		{"Generate", "生成"},
		{"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "注意： 结果字符串可以用于注册次级域名(例如：example.i2p)。若想注册次级域名，请使用 i2pd-tools。"},
		{"Address", "地址"},
		{"Type", "类型"},
		{"EncType", "加密类型"},
		{"Inbound tunnels", "入站隧道"},
		{"ms", "毫秒"},
		{"Outbound tunnels", "出站隧道"},
		{"Tags", "标签"},
		{"Incoming", "传入"},
		{"Outgoing", "传出"},
		{"Destination", "目标"},
		{"Amount", "数量"},
		{"Incoming Tags", "传入标签"},
		{"Tags sessions", "标签会话"},
		{"Status", "状态"},
		{"Local Destination", "本地目标"},
		{"Streams", "流"},
		{"Close stream", "断开流"},
		{"I2CP session not found", "未找到 I2CP 会话"},
		{"I2CP is not enabled", "I2CP 未启用"},
		{"Invalid", "无效"},
		{"Store type", "存储类型"},
		{"Expires", "过期时间"},
		{"Non Expired Leases", "未到期的租约"},
		{"Gateway", "网关"},
		{"TunnelID", "隧道 ID"},
		{"EndDate", "结束日期"},
		{"not floodfill", "非洪泛"},
		{"Queue size", "队列大小"},
		{"Run peer test", "运行群体测试"},
		{"Decline transit tunnels", "拒绝中转隧道"},
		{"Accept transit tunnels", "允许中转隧道"},
		{"Cancel graceful shutdown", "取消计划的停止"},
		{"Start graceful shutdown", "待他人断线后停止"},
		{"Force shutdown", "强制停止"},
		{"Reload external CSS styles", "重载外部 CSS 样式"},
		{"Note: any action done here are not persistent and not changes your config files.", "注意： 此处完成的任何操作都不是永久的，不会更改您的配置文件。"},
		{"Logging level", "日志级别"},
		{"Transit tunnels limit", "中转隧道限制"},
		{"Change", "更换"},
		{"Change language", "更换语言"},
		{"no transit tunnels currently built", "目前未构建中转隧道"},
		{"SAM disabled", "SAM 已禁用"},
		{"no sessions currently running", "没有正在运行的会话"},
		{"SAM session not found", "未找到 SAM 会话"},
		{"SAM Session", "SAM 会话"},
		{"Server Tunnels", "服务器隧道"},
		{"Client Forwards", "客户端转发"},
		{"Server Forwards", "服务器转发"},
		{"Unknown page", "未知页面"},
		{"Invalid token", "无效凭证"},
		{"SUCCESS", "成功"},
		{"Stream closed", "流已关闭"},
		{"Stream not found or already was closed", "流未找到或已关闭"},
		{"Destination not found", "找不到目标"},
		{"StreamID can't be null", "StreamID 不能为空"},
		{"Return to destination page", "返回目标页面"},
		{"You will be redirected in 5 seconds", "您将在5秒内被重定向"},
		{"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
		{"Back to commands list", "返回命令列表"},
		{"Register at reg.i2p", "在 reg.i2p 注册域名"},
		{"Description", "描述"},
		{"A bit information about service on domain", "在此域名上运行的服务的一些信息"},
		{"Submit", "提交"},
		{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
		{"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
		{"Such destination is not found", "找不到此目标"},
		{"Unknown command", "未知指令"},
		{"Command accepted", "已接受指令"},
		{"Proxy error", "代理错误"},
		{"Proxy info", "代理信息"},
		{"Proxy error: Host not found", "代理错误：找不到主机"},
		{"Remote host not found in router's addressbook", "在路由的地址簿中找不到远程主机"},
		{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务上找到这个主机"},
		{"Invalid request", "无效请求"},
		{"Proxy unable to parse your request", "代理无法解析您的请求"},
		{"addresshelper is not supported", "不支持地址助手"},
		{"Host", "主机"},
		{"added to router's addressbook from helper", "将此地址从地址助手添加到地址簿"},
		{"Click here to proceed:", "点击此处继续:"},
		{"Continue", "继续"},
		{"Addresshelper found", "找到地址助手"},
		{"already in router's addressbook", "已在路由器的地址簿中"},
		{"Click here to update record:", "点击此处更新地址簿记录"},
		{"invalid request uri", "无效的 URL 请求"},
		{"Can't detect destination host from request", "无法从请求中检测到目标主机"},
		{"Outproxy failure", "出口代理失效"},
		{"bad outproxy settings", "错误的出口代理设置"},
		{"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内，但未启用出口代理"},
		{"unknown outproxy url", "未知的出口代理地址"},
		{"cannot resolve upstream proxy", "无法解析上游代理"},
		{"hostname too long", "主机名过长"},
		{"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
		{"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
		{"CONNECT error", "连接错误"},
		{"Failed to Connect", "连接失败"},
		{"socks proxy error", "socks 代理错误"},
		{"failed to send request to upstream", "向上游发送请求失败"},
		{"No Reply From socks proxy", "没有来自 socks 代理的回复"},
		{"cannot connect", "无法连接"},
		{"http out proxy not implemented", "http 出口代理未实现"},
		{"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
		{"Host is down", "主机已关闭"},
		{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线，请稍后再试。"},
		{"", ""},
	};

	static std::map<std::string, std::vector<std::string>> plurals
	{
		{"days", {"日"}},
		{"hours", {"时"}},
		{"minutes", {"分"}},
		{"seconds", {"秒"}},
		{"", {""}},
	};

	std::shared_ptr<const i2p::i18n::Locale> GetLocale()
	{
		return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
	}

} // language
} // i18n
} // i2p
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_RESPONSE_HPP
#define HTTP_RESPONSE_HPP

#include "message.hpp"
#include "status_line.hpp"

namespace http {

//--------------------------------
// This class is used to represent
// an http response message
//--------------------------------
class Response : public Message {
private:
  //------------------------------
  // Internal class type aliases
  //------------------------------
  using Code  = status_t;
  //------------------------------
public:
  //------------------------------
  // Constructor to set up a response
  // by providing information for the
  // status line of the response message
  //
  // @param code    - The status code
  // @param version - The version of the message
  //------------------------------
  explicit Response(const Code code = OK, const Version version = Version{}) noexcept;

  //----------------------------------------
  // Constructor to construct a response
  // message from the incoming character
  // stream of data which is a <std::string>
  // object
  //
  // @tparam (std::string) response - The character stream
  //                                  of data
  //
  // @param limit - Capacity of how many fields can
  //                be added
  //----------------------------------------
  template <typename Egress>
  explicit Response(Egress&& response, const Limit limit = 100);

  //----------------------------------------
  // Default copy constructor
  //----------------------------------------
  Response(const Response&) = default;

  //----------------------------------------
  // Default move constructor
  //----------------------------------------
  Response(Response&&) noexcept = default;

  //------------------------------
  // Default destructor
  //------------------------------
  ~Response() noexcept = default;

  //----------------------------------------
  // Default copy assignment operator
  //----------------------------------------
  Response& operator = (const Response&) = default;

  //----------------------------------------
  // Default move assignment operator
  //----------------------------------------
  Response& operator = (Response&&) = default;

  //------------------------------
  // Get the status code of this
  // message
  //
  // @return - The status code of this
  //           message
  //------------------------------
  Code status_code() const noexcept;

  //------------------------------
  // Change the status code of this
  // message
  //
  // @param code - The new status code to set
  //               on this message
  //
  // @return - The object that invoked this method
  //------------------------------
  Response& set_status_code(const Code code) noexcept;

  //----------------------------------------
  // Reset the response message as if it was now
  // default constructed
  //
  // @return - The object that invoked this method
  //----------------------------------------
  virtual Response& reset() noexcept override;

  //-----------------------------------
  // Get a string representation of this
  // class
  //
  // @return - A string representation
  //-----------------------------------
  virtual std::string to_string() const override;

  //-----------------------------------
  // Operator to transform this class
  // into string form
  //-----------------------------------
  operator std::string () const;
  //-----------------------------------
private:
  //------------------------------
  // Class data members
  Status_line status_line_;
  //------------------------------
}; //< class Response

/**--v----------- Implementation Details -----------v--**/

inline Response::Response(const Code code, const Version version) noexcept:
  status_line_{version, code}
{}

template <typename Egress>
inline Response::Response(Egress&& response, const Limit limit) :
  Message{limit},
  status_line_{response}
{
  add_headers(std::forward<Egress>(response));
  auto start_of_body = response.find("\r\n\r\n");
  if (start_of_body not_eq std::string::npos) {
    add_body(response.substr(start_of_body + 4));
  }
}

inline Response::Code Response::status_code() const noexcept {
  return static_cast<status_t>(status_line_.get_code());
}

inline Response& Response::set_status_code(const Code code) noexcept {
  status_line_.set_code(code);
  return *this;
}

inline Response& Response::reset() noexcept {
  Message::reset();
  return set_status_code(OK);
}

inline std::string Response::to_string() const {
  return *this;
}

inline Response::operator std::string () const {
  std::ostringstream res;
  //-----------------------------------
  res << status_line_
      << Message::to_string();
  //-----------------------------------
  return res.str();
}

inline Response& operator << (Response& res, const Header_set& headers) {
  for (const auto& field : headers) {
    res.add_header(field.first, field.second);
  }
  return res;
}

inline Response_ptr make_response(buffer_t buf, const size_t len) {
  return std::make_unique<Response>(std::string{reinterpret_cast<char*>(buf.get()), len});
}

inline std::ostream& operator << (std::ostream& output_device, const Response& res) {
  return output_device << res.to_string();
}

/**--^----------- Implementation Details -----------^--**/

} //< namespace http

#endif //< HTTP_RESPONSE_HPP
<commit_msg>Refactored http::Response<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_RESPONSE_HPP
#define HTTP_RESPONSE_HPP

#include "message.hpp"
#include "status_line.hpp"

namespace http {

/**
 * @brief This class is used to represent
 * an HTTP response message
 */
class Response : public Message {
private:
  //------------------------------
  // Internal class type aliases
  using Code  = status_t;
  //------------------------------
public:
  /**
   * @brief Constructor to set up a response
   * by providing information for the
   * status line of the response message
   *
   * @param code:
   * The status code
   *
   * @param version:
   * The version of the message
   */
  explicit Response(const Code code = OK, const Version version = Version{}) noexcept;

  /**
   * @brief Construct a response message from the
   * incoming character stream of data which is a
   * {std::string} object
   *
   * @tparam T response:
   * The character stream of data
   *
   * @param limit:
   * Capacity of how many fields can be added to the header section
   */
  template
  <
    typename T,
    typename = std::enable_if_t
               <std::is_same
               <std::string, std::remove_const_t
               <std::remove_reference_t<T>>>::value>
  >
  explicit Response(T&& response, const Limit limit = 100);

  /**
   * @brief  Default copy constructor
   */
  Response(const Response&) = default;

  /**
   * @brief Default move constructor
   */
  Response(Response&&) noexcept = default;

  /**
   * @brief Default destructor
   */
  ~Response() noexcept = default;

  /**
   * @brief Default copy assignment operator
   */
  Response& operator = (const Response&) = default;

  /**
   * @brief Default move assignment operator
   */
  Response& operator = (Response&&) = default;

  /**
   * @brief Get the status code of this message
   *
   * @return The status code of this message
   */
  Code status_code() const noexcept;

  /**
   * @brief Change the status code of this message
   *
   * @param code:
   * The new status code to set on this message
   *
   * @return The object that invoked this method
   */
  Response& set_status_code(const Code code) noexcept;

  /**
   * @brief Reset the response message as if it was now
   * default constructed
   *
   * @return The object that invoked this method
   */
  virtual Response& reset() noexcept override;

  /**
   * @brief Get a string representation of this
   * class
   *
   * @return A string representation
   */
  virtual std::string to_string() const override;

  /**
   * @brief Operator to transform this class
   * into string form
   */
  operator std::string () const;
  //-----------------------------------
private:
  //------------------------------
  // Class data members
  Status_line status_line_;
  //------------------------------
}; //< class Response

/**--v----------- Implementation Details -----------v--**/

inline Response::Response(const Code code, const Version version) noexcept
  : status_line_{version, code}
{}

template <typename Egress, typename>
inline Response::Response(Egress&& response, const Limit limit)
  : Message{limit}
  , status_line_{response}
{
  add_headers(response);
  std::size_t start_of_body;
  if ((start_of_body = response.find("\r\n\r\n")) not_eq std::string::npos) {
    add_body(response.substr(start_of_body + 4));
  } else if ((start_of_body = response.find("\n\n")) not_eq std::string::npos) {
    add_body(response.substr(start_of_body + 2));
  }
}

inline Response::Code Response::status_code() const noexcept {
  return static_cast<status_t>(status_line_.get_code());
}

inline Response& Response::set_status_code(const Code code) noexcept {
  status_line_.set_code(code);
  return *this;
}

inline Response& Response::reset() noexcept {
  Message::reset();
  return set_status_code(OK);
}

inline std::string Response::to_string() const {
  std::ostringstream res;
  //-----------------------------------
  res << status_line_
      << Message::to_string();
  //-----------------------------------
  return res.str();
}

inline Response::operator std::string () const {
  return to_string();
}

inline Response& operator << (Response& res, const Header_set& headers) {
  for (const auto& field : headers) {
    res.add_header(field.first, field.second);
  }
  return res;
}

inline Response_ptr make_response(buffer_t buf, const size_t len) {
  return std::make_unique<Response>(std::string{reinterpret_cast<char*>(buf.get()), len});
}

inline std::ostream& operator << (std::ostream& output_device, const Response& res) {
  return output_device << res.to_string();
}

/**--^----------- Implementation Details -----------^--**/

} //< namespace http

#endif //< HTTP_RESPONSE_HPP
<|endoftext|>


<commit_before>/******************************************************************************/
/*  Copyright 2015 Lucas Dário and Renato Cordeiro Ferreira                   */
/*                                                                            */
/*  Licensed under the Apache License, Version 2.0 (the "License");           */
/*  you may not use this file except in compliance with the License.          */
/*  You may obtain a copy of the License at                                   */
/*                                                                            */
/*      http://www.apache.org/licenses/LICENSE-2.0                            */
/*                                                                            */
/*  Unless required by applicable law or agreed to in writing, software       */
/*  distributed under the License is distributed on an "AS IS" BASIS,         */
/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
/*  See the License for the specific language governing permissions and       */
/*  limitations under the License.                                            */
/******************************************************************************/

#ifndef HPP_FORK_DEFINED
#define HPP_FORK_DEFINED

// Standard headers
#include <queue>
#include <mutex>
#include <memory>
#include <thread>
#include <iostream>
#include <condition_variable>

// Internal headers
#include "Philosopher.hpp"

// Forward declaration
class Fork;

// Pointer
using ForkPtr = std::shared_ptr<Fork>;

// Class
class Fork {
 public:
  // Static methods
  template<typename... Args>
  static ForkPtr make(Args... args) {
    return ForkPtr(new Fork(std::forward<Args>(args)...));
  }

  // Synchronized methods
  void take() {
    std::unique_lock<std::mutex> lock(_mutex);
    wait(lock, not_using);
  }

  void drop() {
    std::unique_lock<std::mutex> lock(_mutex);
    signal(not_using);
  }

  // Concrete methods
  unsigned int position() const {
    return _position;
  }

  void position(unsigned int position) {
    _position = position;
  }

 private:
  // Instance variables
  unsigned int _position;

  // Monitor variables
  std::mutex _mutex;
  std::queue<std::thread::id> _waiting;
  std::condition_variable not_using;

  // Monitor methods
  void wait(std::unique_lock<std::mutex> &lock,
            std::condition_variable &cv) {

    _waiting.push(std::this_thread::get_id());
    cv.wait(lock, [this]() { return _waiting.front() == std::this_thread::get_id(); });
    _waiting.pop();
  }

  void signal(std::condition_variable &cv) {
    cv.notify_all();
  }
};

#endif
<commit_msg>Fix wait() and signal() from monitor. The fork now know when it's available or not<commit_after>/******************************************************************************/
/*  Copyright 2015 Lucas Dário and Renato Cordeiro Ferreira                   */
/*                                                                            */
/*  Licensed under the Apache License, Version 2.0 (the "License");           */
/*  you may not use this file except in compliance with the License.          */
/*  You may obtain a copy of the License at                                   */
/*                                                                            */
/*      http://www.apache.org/licenses/LICENSE-2.0                            */
/*                                                                            */
/*  Unless required by applicable law or agreed to in writing, software       */
/*  distributed under the License is distributed on an "AS IS" BASIS,         */
/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  */
/*  See the License for the specific language governing permissions and       */
/*  limitations under the License.                                            */
/******************************************************************************/

#ifndef HPP_FORK_DEFINED
#define HPP_FORK_DEFINED

// Standard headers
#include <queue>
#include <mutex>
#include <memory>
#include <thread>
#include <iostream>
#include <condition_variable>

// Internal headers
#include "Philosopher.hpp"

// Forward declaration
class Fork;

// Pointer
using ForkPtr = std::shared_ptr<Fork>;

// Class
class Fork {
 public:
  // Static methods
  template<typename... Args>
  static ForkPtr make(Args... args) {
    return ForkPtr(new Fork(std::forward<Args>(args)...));
  }

  // Synchronized methods
  void take() {
    std::unique_lock<std::mutex> lock(_mutex);
    wait(lock, not_using);
  }

  void drop() {
    std::unique_lock<std::mutex> lock(_mutex);
    signal(not_using);
  }

  // Concrete methods
  unsigned int position() const {
    return _position;
  }

  void position(unsigned int position) {
    _position = position;
  }

 private:
  // Instance variables
  unsigned int _position;

  // Monitor variables
  std::mutex _mutex;
  std::queue<std::thread::id> _waiting;
  std::condition_variable not_using;
  bool available = true;

  // Monitor methods
  void wait(std::unique_lock<std::mutex> &lock,
            std::condition_variable &cv) {
    _waiting.push(std::this_thread::get_id());
    cv.wait(lock, [this]() { return std::this_thread::get_id() == _waiting.front() && available; });
    available = false;
    _waiting.pop();
  }

  void signal(std::condition_variable &cv) {
    available = true;
    cv.notify_all();
  }
};

#endif
<|endoftext|>


<commit_before>#pragma once

#define AUSS_HPP

#include <sstream>

#ifdef AUSS_USE_OWN_NAMESPACE
	#ifndef AUSS_OWN_NAMESPACE_NAME
	#define AUSS_OWN_NAMESPACE_NAME auss
	#endif
namespace AUSS_OWN_NAMESPACE_NAME {
#endif

class AutoStringStream {
public:
	AutoStringStream() : m_stream() {}
	virtual ~AutoStringStream() {}

	template<typename T>
	AutoStringStream&  operator<<(const T&  arg) {
		m_stream << arg;
		return *this;
	}

	AutoStringStream&  operator<<(const bool arg) {
		m_stream << (arg ? "true" : "false");
		return *this;
	}

	operator std::string() const {
		return m_stream.str();
	}

	const std::string  to_string() const {
		return m_stream.str();
	}
private:
	std::stringstream  m_stream;
};

typedef AutoStringStream auss_t;

#ifdef AUSS_USE_OWN_NAMESPACE
}
#endif
<commit_msg>AUSS_CUSTOM_TYPEDEF<commit_after>#pragma once

#define AUSS_HPP

#include <sstream>

#ifdef AUSS_USE_OWN_NAMESPACE
	#ifndef AUSS_OWN_NAMESPACE_NAME
	#define AUSS_OWN_NAMESPACE_NAME auss
	#endif
namespace AUSS_OWN_NAMESPACE_NAME {
#endif

class AutoStringStream {
public:
	AutoStringStream() : m_stream() {}
	virtual ~AutoStringStream() {}

	template<typename T>
	AutoStringStream&  operator<<(const T&  arg) {
		m_stream << arg;
		return *this;
	}

	AutoStringStream&  operator<<(const bool arg) {
		m_stream << (arg ? "true" : "false");
		return *this;
	}

	operator std::string() const {
		return m_stream.str();
	}

	const std::string  to_string() const {
		return m_stream.str();
	}
private:
	std::stringstream  m_stream;
};

#ifndef AUSS_CUSTOM_TYPEDEF
typedef AutoStringStream auss_t;
#endif

#ifdef AUSS_USE_OWN_NAMESPACE
}
#endif
<|endoftext|>


<commit_before>#ifndef __JCONER_JSON_HPP__
#define __JCONER_JSON_HPP__

#include "token.hpp"
#include "value.hpp"
#include "stream.hpp"
#include "parser.hpp"
#include "dump.hpp"

#endif
<commit_msg>Add error.hpp in json.hpp<commit_after>#ifndef __JCONER_JSON_HPP__
#define __JCONER_JSON_HPP__

#include "token.hpp"
#include "value.hpp"
#include "stream.hpp"
#include "parser.hpp"
#include "dump.hpp"
#include "error.hpp"

#endif
<|endoftext|>