Exemplo n.º 1
0
int dumpNBT_list(NBT_list *input, uint8 *buffer)
{
    int curpos=0;
    buffer[curpos]=TAG_LIST;
    curpos++;
    curpos+=dumpNBT_string(&buffer[curpos],input->name);

    buffer[curpos]=input->tagId;
    curpos++;

    putSint32(&buffer[curpos],input->length);
    curpos+=4;

    for(int i=0; i<input->length; i++)
    {
        switch(input->tagId)
        {
        case TAG_BYTE:
            buffer[curpos]=*(char *)input->items[i];
            curpos++;
            break;
        case TAG_SHORT:
            putSint16(&buffer[curpos], *(int *)input->items[i]);
            curpos+=2;
            break;
        case TAG_INT:
            putSint32(&buffer[curpos], *(int *)input->items[i]);
            curpos+=4;
            break;
        case TAG_LONG:
            putSint64(&buffer[curpos], *(long long *)input->items[i]);
            curpos+=8;
            break;
        case TAG_FLOAT:
            putFloat(&buffer[curpos], *(float *)input->items[i]);
            curpos+=4;
            break;
        case TAG_DOUBLE:
            putDouble(&buffer[curpos], *(double *)input->items[i]);
            curpos+=8;
            break;
        case TAG_STRING:
            curpos+=dumpNBT_string(&buffer[curpos],*(std::string *)input->items[i]);
            break;
        case TAG_BYTE_ARRAY:
            curpos+=dumpNBT_byte_array((NBT_byte_array *)input->items[i], &buffer[curpos],true);
            break;
        case TAG_COMPOUND:
            curpos+=dumpNBT_struct((NBT_struct *)input->items[i], &buffer[curpos],true);
            break;
        }
    }

    return curpos;
}
Exemplo n.º 2
0
int dumpNBT_struct(NBT_struct *input, uint8 *buffer, bool list)
{
    int curpos=0;

    if(!list)
    {
        buffer[curpos]=TAG_COMPOUND;
        curpos++;
        curpos+=dumpNBT_string(&buffer[curpos],input->name);
    }

    //Dump all values
    for(unsigned int i=0; i<input->values.size(); i++)
    {
        curpos+=dumpNBT_value(&input->values[i],&buffer[curpos]);
    }

    //Dump byte arrays
    for(unsigned int i=0; i<input->byte_arrays.size(); i++)
    {
        curpos+=dumpNBT_byte_array(&input->byte_arrays[i],&buffer[curpos]);
    }

    //Dump lists
    for(unsigned int i=0; i<input->lists.size(); i++)
    {
        curpos+=dumpNBT_list(&input->lists[i],&buffer[curpos]);
    }

    //Dump compounds
    for(unsigned int i=0; i<input->compounds.size(); i++)
    {
        curpos+=dumpNBT_struct(&input->compounds[i],&buffer[curpos]);
    }

    buffer[curpos]=0x00; //TAG_END
    curpos++;

    //Total size
    return curpos;
}
Exemplo n.º 3
0
int PacketHandler::complex_entities(User *user)
{
  if(user->buffer.size() < 12)
    return PACKET_NEED_MORE_DATA;

  int curpos = 0;
  unsigned int i;
  uint8 intArray[4];
  uint8 shortArray[2];

  std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+4, intArray);
  int x = getSint32(&intArray[0]);
  curpos += 4;
  std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+2, shortArray);
  int y = getSint16(&shortArray[0]);
  curpos += 2;
  std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+4, intArray);
  int z = getSint32(&intArray[0]);
  curpos += 4;

  std::copy(user->buffer.begin()+curpos, user->buffer.begin()+curpos+2, shortArray);
  int len = getSint16(&shortArray[0]);
  curpos += 2;

  // Wait for whole message
  if(user->buffer.size() < (unsigned int)curpos+len)
    return PACKET_NEED_MORE_DATA;

  //ToDo: check len
  uint8 *buffer = new uint8[len];
  for(i = 0; i < (uint32)len; i++)
  {
    buffer[i] = user->buffer[curpos+i];
  }
  curpos += len;

  user->buffer.erase(user->buffer.begin(), user->buffer.begin()+curpos);

  uint8 block, meta;
  Map::get().getBlock(x, y, z, &block, &meta);

  //We only handle chest for now
  if(block != BLOCK_CHEST)
  {
    delete[] buffer;
    return curpos;
  }


  //Calculate uncompressed size and allocate memory
  uLongf uncompressedSize   = ALLOCATE_NBTFILE; //buffer[len-3] + (buffer[len-2]<<8) + (buffer[len-1]<<16) + (buffer[len]<<24);
  uint8 *uncompressedBuffer = new uint8[uncompressedSize];
  
  //Initialize zstream to handle gzip format
  z_stream zstream;
  zstream.zalloc    = (alloc_func)0;
  zstream.zfree     = (free_func)0;
  zstream.opaque    = (voidpf)0;
  zstream.next_in   = buffer;
  zstream.next_out  = uncompressedBuffer;
  zstream.avail_in  = len;
  zstream.avail_out = uncompressedSize;
  zstream.total_in  = 0;
  zstream.total_out = 0;
  zstream.data_type = Z_BINARY;
  inflateInit2(&zstream, 1+MAX_WBITS);
  //Uncompress
  if(/*int state=*/inflate(&zstream, Z_FULL_FLUSH)!=Z_OK)
  {
      inflateEnd(&zstream);
  }
  //Get size
  uncompressedSize  = zstream.total_out;
  
  //Push data to NBT struct
  NBT_struct newObject;
  TAG_Compound(uncompressedBuffer, &newObject, true);

  //These are not needed anymore
  delete[] buffer;
  delete[] uncompressedBuffer;

  //Get chunk position
  int block_x = blockToChunk(x);
  int block_z = blockToChunk(z);
  uint32 chunkID;

  NBT_struct *theEntity = 0;


  //Load map
  if(Map::get().loadMap(block_x, block_z))
  {
    Map::get().posToId(block_x, block_z, &chunkID);
    NBT_struct mapData = Map::get().maps[chunkID];

    //Try to find entitylist from the chunk
    NBT_list *entitylist = get_NBT_list(&mapData, "TileEntities");

    //If list exists
    if(entitylist)
    {
      //Verify list type
      if(entitylist->tagId != TAG_COMPOUND)
      {
        //If wrong type, recreate
        freeNBT_list(entitylist);
        for(i = 0; i < mapData.lists.size(); i++)
        {
          if(mapData.lists[i].name == "TileEntities")
          {
            //Destroy old list
            freeNBT_list(&mapData.lists[i]);
            mapData.lists.erase(mapData.lists.begin()+i);
            break;
          }
        }
        
        //New list
        NBT_list newlisting;  
        newlisting.name   = "TileEntities";
        newlisting.tagId  = TAG_COMPOUND;
        newlisting.length = 0;
        mapData.lists.push_back(newlisting);

        entitylist = get_NBT_list(&mapData, "TileEntities");
      }

      NBT_struct **entities = (NBT_struct **)entitylist->items;
      bool entityExists     = false;
      int existingID        = -1;

      //Search for mathing entity in the list
      for(int i = 0; i < entitylist->length; i++)
      {
        NBT_struct *entity = entities[i];
        std::string id;

        //Get ID
        if(get_NBT_value(entity, "id", &id))
        {
          int entity_x, entity_y, entity_z;
          if(!get_NBT_value(entity, "x", &entity_x) ||
             !get_NBT_value(entity, "y", &entity_y) ||
             !get_NBT_value(entity, "z", &entity_z))
          {
            continue;
          }

          //Check for mathing blocktype and ID
          if(block == BLOCK_CHEST && id == "Chest")
          {
            if(x == entity_x && y == entity_y && z == entity_z)
            {
              entityExists = true;
              theEntity    = entity;
              existingID   = i;
              break;
            }
          }
        }
      } //End For entitylist

      //Generate struct
      theEntity = new NBT_struct;
      NBT_value value;

      //Push ID
      value.type  = TAG_STRING;
      value.name  = "id";
      std::string *name =  new std::string;
      value.value = (void *)name;
      *(std::string *)value.value = "Chest";
      theEntity->values.push_back(value);

      //Position
      value.type  = TAG_INT;
      value.name  = "x";
      value.value = (void *)new int;
      *(int *)value.value = x;
      theEntity->values.push_back(value);

      value.name  = "y";
      value.value = (void *)new int;
      *(int *)value.value = y;
      theEntity->values.push_back(value);

      value.name  = "z";
      value.value = (void *)new int;
      *(int *)value.value = z;
      theEntity->values.push_back(value);

      //Put special chest items
      if(block == BLOCK_CHEST)
      {
        NBT_list *newlist = get_NBT_list(&newObject, "Items");
        if(!newlist)
        {
          //std::cout << "Items not found!" << std::endl;
          return curpos;
        }
        NBT_list itemlist;
        itemlist.name   = "Items";
        itemlist.tagId  = TAG_COMPOUND;
        itemlist.length = newlist->length;
        itemlist.items  = (void **)new NBT_struct *[itemlist.length];

        NBT_struct **structlist = (NBT_struct **)itemlist.items;
        for(int i = 0; i < itemlist.length; i++)
        {
          structlist[i]        = new NBT_struct;
          char type_char;
          sint16 type_sint16;

          //Generate struct
          value.type             = TAG_BYTE;
          value.name             = "Count";          
          get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Count", &type_char);
          value.value            = (void *)new char;
          *(char *)value.value   = type_char;
          structlist[i]->values.push_back(value);

          value.type             = TAG_BYTE;
          value.name             = "Slot";
          get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Slot", &type_char);
          value.value            = (void *)new char;
          *(char *)value.value   = type_char;
          structlist[i]->values.push_back(value);

          value.type             = TAG_SHORT;
          value.name             = "Damage";          
          get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "Damage", &type_sint16);
          value.value            = (void *)new sint16;
          *(sint16 *)value.value = type_sint16;
          structlist[i]->values.push_back(value);

          value.type             = TAG_SHORT;
          value.name             = "id";
          get_NBT_value((NBT_struct *)((NBT_struct **)newlist->items)[i], "id", &type_sint16);
          value.value            = (void *)new sint16;
          *(sint16 *)value.value = type_sint16;
          structlist[i]->values.push_back(value);
        }

        theEntity->lists.push_back(itemlist);
      }
      
      //If entity doesn't exist in the list, resize the list to fit it in
      if(!entityExists)
      {
        
        //ToDo: try this!
        NBT_struct **newlist = new NBT_struct *[entitylist->length+1];
        NBT_struct **oldlist = (NBT_struct **)entitylist->items;
        uint8 *structbuffer  = new uint8[ALLOCATE_NBTFILE];        
        for(int i = 0; i < entitylist->length; i++)
        {
          newlist[i] = new NBT_struct;
          dumpNBT_struct(oldlist[i],structbuffer);
          TAG_Compound(structbuffer, newlist[i],true);
          freeNBT_struct(oldlist[i]);
          oldlist[i] = NULL;
        }
        
        delete [] structbuffer;
        entitylist->length++;
        entitylist->items = (void **)newlist;
        delete [] (NBT_struct **)oldlist;
        newlist[entitylist->length-1] = theEntity;
        
      }
      //If item exists, replace the old with the new
      else
      {
        //Destroy old entitylist
        NBT_struct **oldlist = (NBT_struct **)entitylist->items;
        freeNBT_struct(oldlist[existingID]);
        //Replace with the new
        oldlist[existingID]  = theEntity;
      }

      //Mark chunk as changed
      Map::get().mapChanged[chunkID] = true;
      
    } //If entity exists
  } //If loaded map

  //Send complex entity packet to others
  if(theEntity)
  {
    uint8 *structdump = new uint8[ALLOCATE_NBTFILE];
    uint8 *packetData = new uint8[ALLOCATE_NBTFILE];
    int dumped        = dumpNBT_struct(theEntity, structdump);
    uLongf written    = ALLOCATE_NBTFILE;

    z_stream zstream2;
    zstream2.zalloc    = Z_NULL;
    zstream2.zfree     = Z_NULL;
    zstream2.opaque    = Z_NULL;
    zstream2.next_out  = &packetData[13];
    zstream2.next_in   = structdump;
    zstream2.avail_in  = dumped;
    zstream2.avail_out = written;
    zstream2.total_out = 0;
    zstream2.total_in  = 0;
    deflateInit2(&zstream2, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15+MAX_WBITS, 8,
                 Z_DEFAULT_STRATEGY);

    if(int state=deflate(&zstream2,Z_FULL_FLUSH)!=Z_OK)
    {
      std::cout << "Error in deflate: " << state << std::endl;
      deflateEnd(&zstream2);
    }
    else
    {
      written = zstream2.total_out;
      packetData[0] = 0x3b; //Complex Entities
      putSint32(&packetData[1],x);
      putSint16(&packetData[5],y);
      putSint32(&packetData[7],z);
      putSint16(&packetData[11], (sint16)written);
      user->sendAll((uint8 *)&packetData[0], 13+written);
    }

    delete [] packetData;
    delete [] structdump;
  }





  return curpos;
}