// Physics loop bool Physics::update() { if(!enabled) { return true; } // Check if needs to be updated if(simList.empty()) { return true; } clock_t starttime = clock(); std::vector<sint32> toRemove; std::vector<vec> toAdd; Screen::get()->log("Simulating " + dtos(simList.size()) + " items!"); uint32 listSize = simList.size(); // Iterate each simulation for(uint32 simIt = 0; simIt < listSize; simIt++) { vec pos = simList[simIt].blocks[0].pos; // Blocks uint8 block, meta; Map::get()->getBlock(pos, &block, &meta); simList[simIt].blocks[0].id = block; simList[simIt].blocks[0].meta = meta; // Water simulation if(simList[simIt].type == TYPE_WATER) { if(isWaterBlock(block)) { sint32 it = 0; //for(sint32 it=simList[simIt].blocks.size()-1; it>=0; it--) { bool havesource = false; // Search for water source if this is not the source if(simList[simIt].blocks[it].id != BLOCK_STATIONARY_WATER) { for(int i = 0; i < 6; i++) { vec local(pos); switch(i) { case 0: local += vec( 0, 1, 0); break; //y++ case 1: local += vec( 1, 0, 0); break; //x++ case 2: local += vec(-1, 0, 0); break; //x-- case 3: local += vec( 0, 0, 1); break; //z++ case 4: local += vec( 0, 0, -1); break; //z-- case 5: local += vec( 0, -1, 0); break; //y-- } // Search neighboring water blocks for source current if (Map::get()->getBlock(local, &block, &meta) && isWaterBlock(block)) { // is this the source block if(i != 5 && (block == BLOCK_STATIONARY_WATER || (meta&0x07) < (simList[simIt].blocks[it].meta&0x07) || i == 0)) { havesource = true; } //Else we have to search for source to this block also else if(i == 5 || (meta&0x07) > (simList[simIt].blocks[it].meta&0x07)) { toAdd.push_back(local); } } } } //Stationary water block is the source else { havesource = true; } //If no source, dry block away if(!havesource) { //This block will change so add surrounding blocks to simulation for(uint32 i = 0; i < toAdd.size(); i++) { addSimulation(toAdd[i]); } //If not dried out yet if(!(simList[simIt].blocks[it].meta&0x8) && (simList[simIt].blocks[it].meta&0x07) < M7) { // Set new water level block = BLOCK_WATER; meta = simList[simIt].blocks[it].meta+1; Map::get()->setBlock(pos, block, meta); Map::get()->sendBlockChange(pos, block, meta); toRemove.push_back(simIt); addSimulation(pos); // Update simulation meta information // simList[simIt].blocks[it].meta = meta; } //Else this block has dried out else { //Clear and remove simulation Map::get()->setBlock(pos, BLOCK_AIR, 0); Map::get()->sendBlockChange(pos, BLOCK_AIR, 0); toRemove.push_back(simIt); //If below this block has another waterblock, simulate it also if(Map::get()->getBlock(pos - vec(0, 1, 0), &block, &meta) && isWaterBlock(block)) addSimulation(pos - vec(0, 1, 0)); } } //Have source! else { toAdd.clear(); vec belowPos(pos - vec(0, 1, 0)); // If below is free to fall if(Map::get()->getBlock(belowPos, &block, &meta) && mayFallThrough(block)) { // Set new fallblock there block = BLOCK_WATER; meta = M_FALLING; Map::get()->setBlock(belowPos, block, meta); Map::get()->sendBlockChange(belowPos, block, meta); // Change simulation-block to current block toRemove.push_back(simIt); addSimulation(belowPos); } //Else if spreading to sides //If water level is at minimum, dont simulate anymore else if((simList[simIt].blocks[it].meta&M7) != M7) { for(int i = 0; i < 4; i++) { vec local(pos); switch(i) { case 0: local += vec( 1, 0, 0); break; case 1: local += vec(-1, 0, 0); break; case 2: local += vec( 0, 0, 1); break; case 3: local += vec( 0, 0, -1); break; } if(Map::get()->getBlock(local, &block, &meta) && mayFallThrough(block)) { //Decrease water level each turn if(!isWaterBlock(block) || meta > (simList[simIt].blocks[it].meta&0x07)+1) { meta = (simList[simIt].blocks[it].meta&0x07)+1; Map::get()->setBlock(local, BLOCK_WATER, meta); Map::get()->sendBlockChange(local, BLOCK_WATER, meta); addSimulation(local); } } } // End for i=0:3 //Remove this block from simulation toRemove.push_back(simIt); } //Water level at minimum else { //Remove this block from simulation toRemove.push_back(simIt); } } } } //Block has changes else { //Remove this block from simulation toRemove.push_back(simIt); } } else { //Remove this block from simulation toRemove.push_back(simIt); } } std::vector<int>::reverse_iterator rit; for ( rit = toRemove.rbegin() ; rit < toRemove.rend(); ++rit ) { simList.erase(simList.begin()+*rit); } clock_t endtime = clock()-starttime; Screen::get()->log("Exit simulation, took " + dtos(endtime*1000/CLOCKS_PER_SEC) + " ms, " + dtos(simList.size()) + " items left"); return true; }
// Physics loop bool Physics::update() { updateFall(); updateMinecart(); if (!enabled) { return true; } // Check if needs to be updated if (simList.empty()) { return true; } std::vector<vec> toAdd; std::vector<vec> toRem; std::set<vec> changed; clock_t starttime = clock(); LOG(INFO, "Physics", "Simulating " + dtos(simList.size()) + " items!"); uint32_t listSize = simList.size(); for (uint32_t simIt = 0; simIt < listSize; simIt++) { vec pos = simList[simIt].blocks[0].pos; // Blocks uint8_t block, meta; ServerInstance->map(map)->getBlock(pos, &block, &meta); simList[simIt].blocks[0].id = block; simList[simIt].blocks[0].meta = meta; bool used = false; for (int i = 0; i < 5; i++) { vec local(pos); bool falling = false; switch (i) { case 0: local += vec(0, -1, 0); // First tries to go down falling = true; break; case 1: local += vec(1, 0, 0); // Might be bad to have the 4 cardinal dir' // so predictable break; case 2: local += vec(-1, 0, 0); break; case 3: local += vec(0, 0, 1); break; case 4: local += vec(0, 0, -1); break; case 5: // local += vec(0,1,0); // Going UP break; } uint8_t newblock, newmeta; ServerInstance->map(map)->getBlock(pos, &block, &meta); ServerInstance->map(map)->getBlock(local, &newblock, &newmeta); if (!isLiquidBlock(block)) { toRem.push_back(pos); break; } if ((isWaterBlock(newblock) && isWaterBlock(block)) || (isLavaBlock(newblock) && isLavaBlock(block)) || (isLiquidBlock(block) && mayFallThrough(newblock))) { if (falling && !isLiquidBlock(newblock)) { ServerInstance->map(map)->setBlock(local, block, meta); changed.insert(local); ServerInstance->map(map)->setBlock(pos, BLOCK_AIR, 0); changed.insert(pos); toRem.push_back(pos); toAdd.push_back(local); used = true; continue; } if (falling && isLiquidBlock(newblock)) { int top = 8 - meta; int bot = 8 - newmeta; int volume = top + bot; if (volume > 8) { top = volume - 8; bot = 8; } else { top = 0; bot = volume; } int a_meta = 8 - top; int a_newmeta = 8 - bot; toAdd.push_back(local); if (a_meta == meta && a_newmeta == newmeta) { toRem.push_back(pos); toRem.push_back(local); continue; } if ((isWaterBlock(block) && a_meta < 8) || (isLavaBlock(block) && a_meta < 4)) { ServerInstance->map(map)->setBlock(pos, block, a_meta); changed.insert(pos); } else { ServerInstance->map(map)->setBlock(pos, BLOCK_AIR, 0); changed.insert(pos); } ServerInstance->map(map)->setBlock(local, block, a_newmeta); used = true; toAdd.push_back(local); toAdd.push_back(pos); changed.insert(pos); continue; } if (!isLiquidBlock(newblock)) { if (!falling) { if ((isWaterBlock(block) && meta == 7) || (isLavaBlock(block) && meta >= 3)) { toRem.push_back(pos); break; } } // We are spreading onto dry area. newmeta = 7; ServerInstance->map(map)->setBlock(local, block, newmeta); changed.insert(local); meta++; if (meta < 8) { ServerInstance->map(map)->setBlock(pos, block, meta); changed.insert(pos); } else { ServerInstance->map(map)->setBlock(pos, BLOCK_AIR, 0); changed.insert(pos); toRem.push_back(pos); } toAdd.push_back(local); used = true; continue; } if (meta < newmeta - 1 || (meta == newmeta && falling)) { newmeta --; ServerInstance->map(map)->setBlock(local, block, newmeta); changed.insert(local); meta ++; if (meta < 8) { ServerInstance->map(map)->setBlock(pos, block, meta); changed.insert(pos); } else { ServerInstance->map(map)->setBlock(pos, BLOCK_AIR, 0); changed.insert(pos); toRem.push_back(pos); } toAdd.push_back(local); used = true; continue; } } } if (!used) { toRem.push_back(pos); } } for (int i = int(toRem.size()) - 1; i >= 0; i--) { removeSimulation(toRem[i]); } for (size_t i = 0; i < toAdd.size(); i++) { addSimulation(toAdd[i]); } ServerInstance->map(map)->sendMultiBlocks(changed); clock_t endtime = clock() - starttime; // LOG(INFO, "Physics", "Exit simulation, took " + dtos(endtime * 1000 / CLOCKS_PER_SEC) + " ms, " + dtos(simList.size()) + " items left"); return true; }