void kit(User *user, std::string command, std::deque<std::string> args) { if(!args.empty()) { std::vector<int> kitItems = Conf::get().vValue("kit_" + args[0]); // If kit is found if(!kitItems.empty()) { for(uint32 i=0;i<kitItems.size();i++) { spawnedItem item; item.EID = generateEID(); item.item = kitItems[i]; item.count = 1; item.health=0; item.pos.x() = static_cast<int>(user->pos.x*32 + (rand() % 30)); item.pos.y() = static_cast<int>(user->pos.y*32); item.pos.z() = static_cast<int>(user->pos.z*32 + (rand() % 30)); Map::get().sendPickupSpawn(item); } } else reportError(user, "Kit " + args[0] + " not found"); } }
Mob::Mob() { x = 0; y = 0; z = 0; map = 0; yaw = 0; pitch = 0; meta = 0; UID = generateEID(); }
void PacketHandler::pickup_spawn(uint8 *data, User *user) { uint32 curpos = 4; spawnedItem item; item.EID = generateEID(); item.health = 0; item.item = getSint16(&data[curpos]); curpos += 2; item.count = data[curpos]; curpos++; item.pos.x() = getSint32(&data[curpos]); curpos += 4; item.pos.y() = getSint32(&data[curpos]); curpos += 4; item.pos.z() = getSint32(&data[curpos]); curpos += 4; item.spawnedBy = user->UID; Map::get().sendPickupSpawn(item); }
int PacketHandler::pickup_spawn(User *user) { //uint32_t curpos = 4; //warning: unused variable ‘curpos’ spawnedItem item; item.health = 0; int8_t yaw, pitch, roll; user->buffer >> (int32_t&)item.EID; user->buffer >> (int16_t&)item.item >> (int8_t&)item.count >> (int16_t&)item.health; user->buffer >> (int32_t&)item.pos.x() >> (int32_t&)item.pos.y() >> (int32_t&)item.pos.z(); user->buffer >> yaw >> pitch >> roll; if(!user->buffer) { return PACKET_NEED_MORE_DATA; } user->buffer.removePacket(); item.EID = generateEID(); item.spawnedBy = user->UID; item.spawnedAt = time(NULL); // Modify the position of the dropped item so that it appears in front of user instead of under user int distanceToThrow = 64; float angle = DEGREES_TO_RADIANS(user->pos.yaw + 45); // For some reason, yaw seems to be off to the left by 45 degrees from where you're actually looking? int x = int(cos(angle) * distanceToThrow - sin(angle) * distanceToThrow); int z = int(sin(angle) * distanceToThrow + cos(angle) * distanceToThrow); item.pos += vec(x, 0, z); Mineserver::get()->map(user->pos.map)->sendPickupSpawn(item); return PACKET_OK; }
void ItemProjectile::onRightClick(User* user, Item* item) { int8_t projID = 0; switch(item->getType()) { case ITEM_SNOWBALL: projID = 61; break; case ITEM_EGG: projID = 62; break; case ITEM_BOW: projID = 60; // TODO check arrows and remove one! break; } if(projID != 0) { int32_t EID = generateEID(); Packet pkt; //Entity packet (initialization) pkt << 0x1E << EID; //Spawn snowball on player location // 0x17 == add object, 61 == snowball pkt << 0x17 << EID << (int8_t)projID << (int32_t)(user->pos.x*32) << (int32_t)((user->pos.y+1.5)*32) << (int32_t)(user->pos.z*32); float tempMult = 1.f-((user->pos.pitch/90.f)<0?-(user->pos.pitch/90.f):(user->pos.pitch/90.f)); //Entity velocity pkt << 0x1C << EID << (int16_t)(sinf(-(user->pos.yaw / 360.f) * 2.f*M_PI)*tempMult*32768.f) << (int16_t)(-32768.f*(user->pos.pitch/90.f)) << (int16_t)(cosf(-(user->pos.yaw/ 360.f) * 2.f*M_PI)*tempMult*32768.f); user->sendAll((uint8_t *)pkt.getWrite(), pkt.getWriteLen()); item->decCount(); } }
void PacketHandler::player_digging(uint8 *data, User *user) { int curpos = 0; char status = data[curpos]; curpos++; int x = getSint32(&data[curpos]); curpos += 4; char y = data[curpos]; curpos++; int z = getSint32(&data[curpos]); curpos += 4; //If block broken if(status == BLOCK_STATUS_BLOCK_BROKEN) { uint8 block; uint8 meta; if(Map::get().getBlock(x, y, z, &block, &meta)) { Map::get().sendBlockChange(x, y, z, 0, 0); Map::get().setBlock(x, y, z, 0, 0); uint8 topblock; uint8 topmeta; //Destroy items on top if(Map::get().getBlock(x, y+1, z, &topblock, &topmeta) && (topblock == BLOCK_SNOW || topblock == BLOCK_BROWN_MUSHROOM || topblock == BLOCK_RED_MUSHROOM || topblock == BLOCK_YELLOW_FLOWER || topblock == BLOCK_RED_ROSE || topblock == BLOCK_SAPLING)) { Map::get().sendBlockChange(x, y+1, z, 0, 0); Map::get().setBlock(x, y+1, z, 0, 0); //Others than snow will spawn if(topblock != BLOCK_SNOW) { spawnedItem item; item.EID = generateEID(); item.health = 0; item.item = (int)topblock; item.count = 1; item.pos.x() = x*32; item.pos.y() = (y+1)*32; item.pos.z() = z*32; //Randomize spawn position a bit item.pos.x() += 5+(rand()%22); item.pos.z() += 5+(rand()%22); Map::get().sendPickupSpawn(item); } } if(block != BLOCK_SNOW && (int)block > 0 && (int)block < 255) { spawnedItem item; item.EID = generateEID(); item.health = 0; // Spawn drop according to BLOCKDROPS // Check propability if(BLOCKDROPS.count(block) && BLOCKDROPS[block].probability >= rand()%10000) { item.item = BLOCKDROPS[block].item_id; item.count = BLOCKDROPS[block].count; } else { item.item = (int)block; item.count = 1; } item.pos.x() = x*32; item.pos.y() = y*32; item.pos.z() = z*32; //Randomize spawn position a bit item.pos.x() += 5+(rand()%22); item.pos.z() += 5+(rand()%22); // If count is greater than 0 if(item.count > 0) Map::get().sendPickupSpawn(item); } // Check liquid physics Physics::get().checkSurrounding(vec(x, y, z)); // Block physics for BLOCK_GRAVEL and BLOCK_SAND and BLOCK_SNOW while(Map::get().getBlock(x, y+1, z, &topblock, &topmeta) && (topblock == BLOCK_GRAVEL || topblock == BLOCK_SAND || topblock == BLOCK_SNOW || topblock == BLOCK_BROWN_MUSHROOM || topblock == BLOCK_RED_MUSHROOM || topblock == BLOCK_YELLOW_FLOWER || topblock == BLOCK_RED_ROSE || topblock == BLOCK_SAPLING)) { // Destroy original block Map::get().sendBlockChange(x, y+1, z, 0, 0); Map::get().setBlock(x, y+1, z, 0, 0); Map::get().setBlock(x, y, z, topblock, topmeta); Map::get().sendBlockChange(x, y, z, topblock, topmeta); y++; } } } }
int PacketHandler::player_block_placement(User *user) { if(!user->buffer.haveData(12)) { return PACKET_NEED_MORE_DATA; } int8_t y = 0, direction = 0; int16_t newblock = 0; int32_t x, z = 0; /* replacement of block */ uint8_t oldblock = 0; uint8_t metadata = 0; /* neighbour blocks */ uint8_t block = 0; uint8_t meta = 0; int8_t count = 0; int16_t health = 0; BlockBasic* blockcb; user->buffer >> x >> y >> z >> direction >> newblock; if(newblock >= 0) { if(!user->buffer.haveData(2)) { return PACKET_NEED_MORE_DATA; } user->buffer >> count >> health; } user->buffer.removePacket(); if (!Mineserver::get()->map(user->pos.map)->getBlock(x, y, z, &oldblock, &metadata)) { return PACKET_OK; } // TODO: Handle int16_t itemID's /* if(newblock > 255 && newblock != ITEM_SIGN) { return PACKET_OK; } */ /* Protocol docs say this should be what interacting is. */ if(oldblock != BLOCK_AIR && newblock == -1) { (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("PlayerBlockInteract")))->doAll(user->nick.c_str(), x, y, z); for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(oldblock)) { //This should actually make the boolean do something. Maybe. if(blockcb->onInteract(user, x,y,z,user->pos.map)) { return PACKET_OK; } else { break; } } } } bool foundFromInventory = false; #define INV_TASKBAR_START 36 if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].type == newblock && newblock != -1) { foundFromInventory = true; } #undef INV_TASKBAR_START // TODO: Handle processing of if(direction == -1 || !foundFromInventory) { return PACKET_OK; } // Minecart testing!! if(newblock == ITEM_MINECART && Mineserver::get()->map(user->pos.map)->getBlock(x, y, z, &oldblock, &metadata)) { if (oldblock != BLOCK_MINECART_TRACKS) { return PACKET_OK; } LOG(INFO, "Packets", "Spawn minecart"); int32_t EID=generateEID(); Packet pkt; // MINECART pkt << PACKET_ADD_OBJECT << (int32_t)EID << (int8_t)10 << (int32_t)(x*32+16) << (int32_t)(y*32) << (int32_t)(z*32+16); user->sendAll((uint8_t *)pkt.getWrite(), pkt.getWriteLen()); } if (newblock == -1 && newblock != ITEM_SIGN) { #ifdef _DEBUG LOG(DEBUG, "Packets", "ignoring: "+dtos(newblock)); #endif return PACKET_OK; } if(y < 0) { return PACKET_OK; } #ifdef _DEBUG LOG(DEBUG,"Packets", "Block_placement: "+dtos(newblock)+" ("+dtos(x)+","+dtos((int)y)+","+dtos(z)+") dir: "+dtos((int)direction)); #endif if (direction) { direction = 6-direction; } //if (Mineserver::get()->map()->getBlock(x, y, z, &oldblock, &metadata)) { uint8_t oldblocktop; uint8_t metadatatop; int8_t check_y = y; int32_t check_x = x; int32_t check_z = z; /* client doesn't give us the correct block for lava and water, check block above */ switch(direction) { case BLOCK_BOTTOM: check_y--; break; case BLOCK_TOP: check_y++; break; case BLOCK_NORTH: check_x++; break; case BLOCK_SOUTH: check_x--; break; case BLOCK_EAST: check_z++; break; case BLOCK_WEST: check_z--; break; default: break; } if (Mineserver::get()->map(user->pos.map)->getBlock(check_x, check_y, check_z, &oldblocktop, &metadatatop) && (oldblocktop == BLOCK_LAVA || oldblocktop == BLOCK_STATIONARY_LAVA || oldblocktop == BLOCK_WATER || oldblocktop == BLOCK_STATIONARY_WATER)) { /* block above needs replacing rather then the block sent by the client */ // TODO: Does this require some form of recursion for multiple water/lava blocks? for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onReplace(user, newblock,check_x,check_y,check_z,user->pos.map,direction); } } if ((static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int16_t>*>(Mineserver::get()->plugin()->getHook("BlockReplacePre")))->doUntilFalse(user->nick.c_str(), check_x, check_y, check_z, oldblock, newblock)) { return PACKET_OK; } (static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int16_t>*>(Mineserver::get()->plugin()->getHook("BlockReplacePost")))->doAll(user->nick.c_str(), check_x, check_y, check_z, oldblock, newblock); } else { /* for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onReplace(user, newblock,check_x,check_y,check_z,user->pos.map,direction); } }*/ if ((static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int16_t>*>(Mineserver::get()->plugin()->getHook("BlockReplacePre")))->doUntilFalse(user->nick.c_str(), x, y, z, oldblock, newblock)) { return PACKET_OK; } (static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int16_t>*>(Mineserver::get()->plugin()->getHook("BlockReplacePost")))->doAll(user->nick.c_str(), x, y, z, oldblock, newblock); } if ((static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int8_t>*>(Mineserver::get()->plugin()->getHook("BlockPlacePre")))->doUntilFalse(user->nick.c_str(), x, y, z, newblock,direction)) { return PACKET_OK; } /* We pass the newblock to the newblock's onPlace callback because the callback doesn't know what type of block we're placing. Instead the callback's job is to describe the behaviour when placing the block down, not to place any specifically block itself. */ for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { if(blockcb->onPlace(user, newblock,x,y,z,user->pos.map,direction)){ return PACKET_OK; }else{ break; } } } (static_cast<Hook6<bool,const char*,int32_t,int8_t,int32_t,int16_t,int8_t>*>(Mineserver::get()->plugin()->getHook("BlockPlacePost")))->doAll(user->nick.c_str(), x, y, z, newblock,direction); /* notify neighbour blocks of the placed block */ if (Mineserver::get()->map(user->pos.map)->getBlock(x+1, y, z, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x+1,y,z,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x+1, y, z); } if (Mineserver::get()->map(user->pos.map)->getBlock(x-1, y, z, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x-1,y,z,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x-1, y, z); } if (Mineserver::get()->map(user->pos.map)->getBlock(x, y+1, z, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x,y+1,z,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x, y+1, z); } if (Mineserver::get()->map(user->pos.map)->getBlock(x, y-1, z, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x,y-1,z,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x, y-1, z); } if (Mineserver::get()->map(user->pos.map)->getBlock(x, y, z+1, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x,y,z+1,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x, y, z+1); } if (Mineserver::get()->map(user->pos.map)->getBlock(x, y, z-1, &block, &meta) && block != BLOCK_AIR) { for(int i =0 ; i<Mineserver::get()->plugin()->getBlockCB().size(); i++) { blockcb = Mineserver::get()->plugin()->getBlockCB()[i]; if(blockcb!=NULL && blockcb->affectedBlock(newblock)) { blockcb->onNeighbourPlace(user, newblock,x,y,z-1,user->pos.map,direction); } } (static_cast<Hook4<bool,const char*,int32_t,int8_t,int32_t>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user->nick.c_str(), x, y, z-1); } } // Now we're sure we're using it, lets remove from inventory! #define INV_TASKBAR_START 36 if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].type == newblock && newblock != -1) { //if(newblock<256) { // It's a block user->inv[INV_TASKBAR_START+user->currentItemSlot()].count--; if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].count == 0) { user->inv[INV_TASKBAR_START+user->currentItemSlot()] = Item(); //ToDo: add holding change packet. } user->buffer << (int8_t)PACKET_SET_SLOT << (int8_t)WINDOW_PLAYER << (int16_t)(INV_TASKBAR_START+user->currentItemSlot()) << (int16_t)user->inv[INV_TASKBAR_START+user->currentItemSlot()].type; if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].type != -1) { user->buffer << (int8_t)user->inv[INV_TASKBAR_START+user->currentItemSlot()].count << (int16_t)user->inv[INV_TASKBAR_START+user->currentItemSlot()].health; } } } #undef INV_TASKBAR_START /* TODO: Should be removed from here. Only needed for liquid related blocks? */ Mineserver::get()->physics(user->pos.map)->checkSurrounding(vec(x, y, z)); return PACKET_OK; }
void giveItems(User *user, std::string command, std::deque<std::string> args) { User *tUser = NULL; int itemId = 0, itemCount = 1, itemStacks = 1; 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)) { reportError(user, "Item " + args[1] + " not found."); return; } if(args.size() > 2) { itemCount = atoi(args[2].c_str()); // If multiple stacks itemStacks = roundUpTo(itemCount, 64) / 64; itemCount -= (itemStacks-1) * 64; } } else { reportError(user, "Too few parameters."); return; } 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.pos.x() = static_cast<int>(tUser->pos.x * 32); item.pos.y() = static_cast<int>(tUser->pos.y * 32); item.pos.z() = static_cast<int>(tUser->pos.z * 32); Map::get().sendPickupSpawn(item); } Chat::get().sendMsg(user, COLOR_RED + user->nick + " spawned " + args[1], Chat::ADMINS); } else reportError(user, "User " + args[0] + " not found (see /players)"); }
int PacketHandler::player_block_placement(User *user) { if(!user->buffer.haveData(12)) { return PACKET_NEED_MORE_DATA; } sint8 y, direction; sint16 newblock; sint32 x, z; /* replacement of block */ uint8 oldblock; uint8 metadata; /* neighbour blocks */ uint8 block; uint8 meta; sint8 count,health; user->buffer >> x >> y >> z >> direction >> newblock; if(newblock >= 0) { if(!user->buffer.haveData(2)) { return PACKET_NEED_MORE_DATA; } user->buffer >> count >> health; } user->buffer.removePacket(); if (!Mineserver::get()->map()->getBlock(x, y, z, &oldblock, &metadata)) { return PACKET_OK; } //Check if we need to open a window if(oldblock == BLOCK_CHEST) { //ToDo: check for large chest! Mineserver::get()->inventory()->windowOpen(user,WINDOW_CHEST,x, y, z); return PACKET_OK; } if(oldblock == BLOCK_FURNACE || oldblock == BLOCK_BURNING_FURNACE) { Mineserver::get()->inventory()->windowOpen(user,WINDOW_FURNACE,x, y, z); return PACKET_OK; } if(oldblock == BLOCK_WORKBENCH) { Mineserver::get()->inventory()->windowOpen(user,WINDOW_WORKBENCH,x, y, z); return PACKET_OK; } // TODO: Handle sint16 itemID's if(newblock > 255 && newblock != ITEM_SIGN) { return PACKET_OK; } bool foundFromInventory = false; #define INV_TASKBAR_START 36 if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].type == newblock && newblock != -1) { //Are we really placing this? user->inv[INV_TASKBAR_START+user->currentItemSlot()].count--; if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].count == 0) { user->inv[INV_TASKBAR_START+user->currentItemSlot()] = Item(); //ToDo: add holding change packet. } user->buffer << (sint8)PACKET_SET_SLOT << (sint8)WINDOW_PLAYER << (sint16)(INV_TASKBAR_START+user->currentItemSlot()) << (sint16)user->inv[INV_TASKBAR_START+user->currentItemSlot()].type; if(user->inv[INV_TASKBAR_START+user->currentItemSlot()].type != -1) { user->buffer << (sint8)user->inv[INV_TASKBAR_START+user->currentItemSlot()].count << (sint8)user->inv[INV_TASKBAR_START+user->currentItemSlot()].health; } foundFromInventory = true; } #undef INV_TASKBAR_START // TODO: Handle processing of if(direction == -1 || !foundFromInventory) { return PACKET_OK; } // Minecart testing!! if(newblock == ITEM_MINECART && Mineserver::get()->map()->getBlock(x, y, z, &oldblock, &metadata)) { if (oldblock != BLOCK_MINECART_TRACKS) { return PACKET_OK; } Mineserver::get()->screen()->log("Spawn minecart"); sint32 EID=generateEID(); Packet pkt; // MINECART pkt << PACKET_ADD_OBJECT << (sint32)EID << (sint8)10 << (sint32)(x*32+16) << (sint32)(y*32) << (sint32)(z*32+16); user->sendAll((uint8 *)pkt.getWrite(), pkt.getWriteLen()); } if (newblock == -1 && newblock != ITEM_SIGN) { Mineserver::get()->screen()->log("ignoring: "+dtos(newblock)); return PACKET_OK; } if(y < 0) { return PACKET_OK; } #ifdef _DEBUG Mineserver::get()->screen()->log("Block_placement: "+dtos(newblock)+" ("+dtos(x)+","+dtos((int)y)+","+dtos(z)+") dir: "+dtos((int)direction)); #endif if (direction) { direction = 6-direction; } Callback callback; Function event; Function::invoker_type inv(user, newblock, x, y, z, direction); //if (Mineserver::get()->map()->getBlock(x, y, z, &oldblock, &metadata)) { uint8 oldblocktop; uint8 metadatatop; sint8 check_y = y; sint32 check_x = x; sint32 check_z = z; /* client doesn't give us the correct block for lava and water, check block above */ switch(direction) { case BLOCK_TOP: check_y++; break; case BLOCK_NORTH: check_x++; break; case BLOCK_SOUTH: check_x--; break; case BLOCK_EAST: check_z++; break; case BLOCK_WEST: check_z--; break; default: break; } if (Mineserver::get()->map()->getBlock(check_x, check_y, check_z, &oldblocktop, &metadatatop) && (oldblocktop == BLOCK_LAVA || oldblocktop == BLOCK_STATIONARY_LAVA || oldblocktop == BLOCK_WATER || oldblocktop == BLOCK_STATIONARY_WATER)) { /* block above needs replacing rather then the block sent by the client */ inv = Function::invoker_type(user, newblock, check_x, check_y, check_z, direction); Mineserver::get()->plugin()->runBlockCallback(oldblocktop, "onReplace", inv); if ((static_cast<Hook6<bool,User*,sint32,sint8,sint32,uint8,uint8>*>(Mineserver::get()->plugin()->getHook("BlockReplacePre")))->doUntilFalse(user, check_x, check_y, check_z, oldblock, newblock)) { return PACKET_OK; } (static_cast<Hook6<void,User*,sint32,sint8,sint32,uint8,uint8>*>(Mineserver::get()->plugin()->getHook("BlockReplacePost")))->doAll(user, check_x, check_y, check_z, oldblock, newblock); } else { inv = Function::invoker_type(user, newblock, x, y, z, direction); Mineserver::get()->plugin()->runBlockCallback(oldblock, "onReplace", inv); if ((static_cast<Hook6<bool,User*,sint32,sint8,sint32,uint8,uint8>*>(Mineserver::get()->plugin()->getHook("BlockReplacePre")))->doUntilFalse(user, x, y, z, oldblock, newblock)) { return PACKET_OK; } (static_cast<Hook6<void,User*,sint32,sint8,sint32,uint8,uint8>*>(Mineserver::get()->plugin()->getHook("BlockReplacePost")))->doAll(user, x, y, z, oldblock, newblock); } if ((static_cast<Hook5<bool,User*,sint32,sint8,sint32,uint8>*>(Mineserver::get()->plugin()->getHook("BlockPlacePre")))->doUntilFalse(user, x, y, z, newblock)) { return PACKET_OK; } /* We pass the newblock to the newblock's onPlace callback because the callback doesn't know what type of block we're placing. Instead the callback's job is to describe the behaviour when placing the block down, not to place any specifically block itself. */ inv = Function::invoker_type(user, newblock, x, y, z, direction); Mineserver::get()->plugin()->runBlockCallback(newblock, "onPlace", inv); (static_cast<Hook5<void,User*,sint32,sint8,sint32,uint8>*>(Mineserver::get()->plugin()->getHook("BlockPlacePost")))->doAll(user, x, y, z, newblock); /* notify neighbour blocks of the placed block */ if (Mineserver::get()->map()->getBlock(x+1, y, z, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x+1, y, z, BLOCK_SOUTH); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x+1, y, z); } if (Mineserver::get()->map()->getBlock(x-1, y, z, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x-1, y, z, BLOCK_NORTH); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x-1, y, z); } if (Mineserver::get()->map()->getBlock(x, y+1, z, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x, y+1, z, BLOCK_TOP); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x, y+1, z); } if (Mineserver::get()->map()->getBlock(x, y-1, z, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x, y-1, z, BLOCK_BOTTOM); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x, y-1, z); } if (Mineserver::get()->map()->getBlock(x, y, z+1, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x, y, z+1, BLOCK_WEST); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x, y, z+1); } if (Mineserver::get()->map()->getBlock(x, y, z-1, &block, &meta) && block != BLOCK_AIR) { inv = Function::invoker_type(user, newblock, x, y, z-1, BLOCK_EAST); Mineserver::get()->plugin()->runBlockCallback(block, "onNeighbourPlace", inv); (static_cast<Hook4<void,User*,sint32,sint8,sint32>*>(Mineserver::get()->plugin()->getHook("BlockNeighbourPlace")))->doAll(user, x, y, z-1); } } /* TODO: Should be removed from here. Only needed for liquid related blocks? */ Mineserver::get()->physics()->checkSurrounding(vec(x, y, z)); return PACKET_OK; }