Beispiel #1
0
int TAG_Compound(uint8* input, NBT_struct *output, bool start)
{
    char tagType=1;
    std::string name;
    int curpos=0;

    while(tagType!=0)
    {
        curpos+=TAG_Byte(&input[curpos], &tagType);
        if(tagType==0)
        {
            //std::cout << "TAG_end" << std::endl;
            return curpos;
        }
        curpos+=TAG_String(&input[curpos], &name);
        //std::cout << "Name: " << name << std::endl;
        NBT_value value;
        value.type=tagType;
        value.name=name;
        NBT_byte_array bytearray;
        bytearray.name=name;
        NBT_list list;
        list.name=name;
        NBT_struct compound;
        compound.name=name;

        switch(tagType)
        {
        case TAG_BYTE:
            value.value=(void *)new char;
            curpos+=TAG_Byte(&input[curpos], (char *)value.value);
            output->values.push_back(value);
            break;
        case TAG_SHORT:
            value.value=(void *)new int;
            curpos+=TAG_Short(&input[curpos], (int *)value.value);
            output->values.push_back(value);
            break;
        case TAG_INT:
            value.value=(void *)new int;
            curpos+=TAG_Int(&input[curpos], (int *)value.value);
            output->values.push_back(value);
            break;
        case TAG_LONG:
            value.value=(void *)new long long;
            curpos+=TAG_Long(&input[curpos], (long long *)value.value);
            output->values.push_back(value);
            break;
        case TAG_FLOAT:
            value.value=(void *)new float;
            curpos+=TAG_Float(&input[curpos], (float *)value.value);
            output->values.push_back(value);
            break;
        case TAG_DOUBLE:
            value.value=(void *)new double;
            curpos+=TAG_Double(&input[curpos], (double *)value.value);
            output->values.push_back(value);
            break;
        case TAG_BYTE_ARRAY:
            curpos+=TAG_Byte_Array(&input[curpos], &bytearray);
            //Special handling with lightmaps
            if(bytearray.length==0)
            {
                //If zero sized lightmap, generate a new empty lightmap
                if(bytearray.name=="BlockLight" || bytearray.name=="SkyLight")
                {
                    bytearray.length=16*16*128/2;
                    bytearray.data=new uint8[bytearray.length];
                    memset(bytearray.data, 0, bytearray.length);
                }
            }
            output->byte_arrays.push_back(bytearray);
            break;
        case TAG_STRING:
            value.value=(void *)new std::string;
            curpos+=TAG_String(&input[curpos], (std::string *)value.value);
            output->values.push_back(value);
            break;
        case TAG_LIST:
            curpos+=TAG_List(&input[curpos], &list);
            output->lists.push_back(list);
            break;
        case TAG_COMPOUND:
            if(start)
            {
                curpos+=TAG_Compound(&input[curpos], output);
            }
            else
            {
                curpos+=TAG_Compound(&input[curpos], (NBT_struct *)&compound);
                output->compounds.push_back(compound);
            }
            break;
        }

        if(start)
            break;
    }

    return curpos;
}
Beispiel #2
0
int TAG_List(uint8* input, NBT_list *output)
{
    int curpos=0;
    curpos+=TAG_Byte(&input[curpos],&output->tagId);
    curpos+=TAG_Int(&input[curpos],&output->length);

    //If zero length list
    if(!output->length)
    {
        return curpos;
    }

    switch(output->tagId)
    {
    case TAG_BYTE:
        output->items=(void **)new char *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new char;
            curpos+=TAG_Byte(&input[curpos], (char *)output->items[i]);
        }
        break;
    case TAG_SHORT:
        output->items=(void **)new int *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new int;
            curpos+=TAG_Short(&input[curpos], (int *)output->items[i]);
        }
        break;
    case TAG_INT:
        output->items=(void **)new int *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new int;
            curpos+=TAG_Int(&input[curpos], (int *)output->items[i]);
        }
        break;
    case TAG_LONG:
        output->items=(void **)new long long *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new long long;
            curpos+=TAG_Long(&input[curpos], (long long *)output->items[i]);
        }
        break;
    case TAG_FLOAT:
        output->items=(void **)new float *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new float;
            curpos+=TAG_Float(&input[curpos], (float *)output->items[i]);
        }
        break;
    case TAG_DOUBLE:
        output->items=(void **)new double *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new double;
            curpos+=TAG_Double(&input[curpos], (double *)output->items[i]);
        }
        break;
    case TAG_BYTE_ARRAY:
        output->items=(void **)new NBT_byte_array *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new NBT_byte_array;
            curpos+=TAG_Byte_Array(&input[curpos], (NBT_byte_array *)output->items[i]);
        }
        break;
    case TAG_STRING:
        output->items=(void **)new std::string *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new std::string;
            curpos+=TAG_String(&input[curpos], (std::string *)output->items[i]);
        }
        break;
    case TAG_LIST:
        output->items=(void **)new NBT_list *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new NBT_list;
            curpos+=TAG_List(&input[curpos], (NBT_list *)output->items[i]);
        }
        break;
    case TAG_COMPOUND:
        output->items=(void **)new NBT_struct *[output->length];
        for(int i=0; i<output->length; i++)
        {
            output->items[i]=(void *)new NBT_struct;
            curpos+=TAG_Compound(&input[curpos], (NBT_struct *)output->items[i]);
        }
        break;
    }

    return curpos;
}
Beispiel #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;
}