示例#1
0
// 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;
}
示例#2
0
// 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;
}