void GameStateManager::deserializePlayer(int32_t eid)
{
  PlayerState & player = *m_states[eid];

  const std::string name = m_connection_manager.getNickname(eid);
  const std::string nickhash = sha1::calcToString(name.data(), name.length());
  std::copy(nickhash.begin(), nickhash.end(), player.nickhash.begin());

  if (PROGRAM_OPTIONS.count("verbose")) 
  {
    std::cout << "Player nickname is \"" << name << "\", hash: 0x" << hexify(nickhash)
              << ". Attempting to load player data from disk...";
  }

  std::ifstream playerfile("/tmp/mymap.player." + nickhash, std::ios::binary);

  if (!playerfile)
  {
    if (PROGRAM_OPTIONS.count("verbose"))
    {
      std::cout << " failed. Setting default start data." << std::endl;
    }

    const WorldCoords start_pos(8, 80, 8);

    player.position = RealCoords(wX(start_pos) + 0.5, wY(start_pos) + 0.5, wZ(start_pos) + 0.5);
    player.stance   = wY(start_pos) + 0.5;

    player.setInv(37, ITEM_DiamondPickaxe, 1, 0);
    player.setInv(36, BLOCK_Torch, 50, 0);
    player.setInv(29, ITEM_Coal, 50, 0);
    player.setInv(21, BLOCK_Cobblestone, 60, 0);
    player.setInv(22, BLOCK_IronOre, 60, 0);
    player.setInv(30, BLOCK_Wood, 50, 0);
    player.setInv(38, ITEM_DiamondShovel, 1, 0);
    player.setInv(39, BLOCK_BrickBlock, 64, 0);
    player.setInv(40, BLOCK_Stone, 64, 0);
    player.setInv(41, BLOCK_Glass, 64, 0);
    player.setInv(42, BLOCK_WoodenPlank, 64, 0);
    player.setInv(44, BLOCK_Obsidian, 64, 0);
    player.setInv(43, ITEM_Bucket, 1, 0);

    player.holding = 4;
  }
  else
  {
    if (PROGRAM_OPTIONS.count("verbose"))
    {
      std::cout << " done!" << std::endl;
    }

    const WorldCoords start_pos(8, 80, 8);

    player.position = RealCoords(wX(start_pos) + 0.5, wY(start_pos) + 0.5, wZ(start_pos) + 0.5);
    player.stance   = wY(start_pos) + 0.5;
  }
    
}
예제 #2
0
bool GameStateManager::fall(WorldCoords & wbelow)
{
  // This really shouldn't ever be able to happen...
  if (!m_map.haveChunk(getChunkCoords(wbelow))) return false;

  const Chunk & chunk = m_map.chunk(getChunkCoords(wbelow));

  for ( ; ; wbelow += BLOCK_YMINUS)
  {
    // An item that drops on something hot or out of the world dies.
    if (chunk.blockType(getLocalCoords(wbelow)) == BLOCK_Lava           ||
        chunk.blockType(getLocalCoords(wbelow)) == BLOCK_StationaryLava ||
        chunk.blockType(getLocalCoords(wbelow)) == BLOCK_Fire           ||
        wY(wbelow) < 0 )
    {
      return false; // won't even spawn an item that's died.
    }

    if (!isPassable(EBlockItem(chunk.blockType(getLocalCoords(wbelow))))) break;
  }

  wbelow += BLOCK_YPLUS; // wbelow is now the last passable block

  return true;
}
예제 #3
0
	void Manifold::SetContactData(const glm::vec3& c, const glm::vec3& n, const float p)
	{
		contact = c;
		normal = n;

		// calculate the basis matrix for this contact
		glm::vec3 cX, cY, cZ;
		glm::vec3 wY(0, 1, 0);
		glm::vec3 wX(1, 0, 0);
		glm::mat3 contactBasis;
		cX = normal;
		if (glm::dot(normal, wY) > 0.01f)
		{
			cZ = glm::cross(cX, wY);
		}
		else
		{
			cZ = glm::cross(cX, wX);
		}
		cY = glm::cross(cZ, cX);

		contactBasis[0] = cX;
		contactBasis[1] = cY;
		contactBasis[2] = cZ;
	}
예제 #4
0
void GameStateManager::reactToSuccessfulDig(const WorldCoords & wc, EBlockItem block_type)
{
  // this is just temporary
  std::cout << "Successfully dug at " << wc << " for " << BLOCKITEM_INFO.find(block_type)->second.name << std::endl;

  if (block_type == BLOCK_WoodenDoor || block_type == BLOCK_IronDoor)
  {
    Chunk & chunk = m_map.chunk(getChunkCoords(wc));

    if (wY(wc) < 127 && chunk.blockType(getLocalCoords(wc + BLOCK_YPLUS)) == block_type)
    {
      sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + BLOCK_YPLUS, BLOCK_Air, 0));
      chunk.blockType(getLocalCoords(wc + BLOCK_YPLUS)) = BLOCK_Air;
    }

    if (wY(wc) > 0 && chunk.blockType(getLocalCoords(wc + BLOCK_YMINUS)) == block_type)
    {
      sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + BLOCK_YMINUS, BLOCK_Air, 0));
      chunk.blockType(getLocalCoords(wc + BLOCK_YMINUS)) = BLOCK_Air;
    }

    spawnSomething(block_type == BLOCK_WoodenDoor ? ITEM_WoodenDoor : ITEM_IronDoor, 1, 0, wc);
  }

  else if (block_type != 0)
  {
    spawnSomething(uint16_t(block_type), 1, 0, wc);

    auto interesting_blocks = m_map.blockAlerts().equal_range(wc);

    for (auto it = interesting_blocks.first; it != interesting_blocks.second; ++it)
    {
      if (it->second.type == Map::BlockAlert::SUPPORTS_CANDLE)
      {
        reactToBlockDestruction(wc);
        break;
      }
    }
  }
}
예제 #5
0
void GameStateManager::reactToToggle(const WorldCoords & wc, EBlockItem b)
{
  if (!m_map.haveChunk(getChunkCoords(wc))) return;

  Chunk & chunk = m_map.chunk(getChunkCoords(wc));

  switch (b)
  {
  case BLOCK_WoodenDoor:
  case BLOCK_IronDoor:
    {
      // We don't really care if the door is one, two or three blocks tall,
      // but we'll only treat at most one block above and below the clicked one.

      uint8_t meta = chunk.getBlockMetaData(getLocalCoords(wc));
      meta ^= 0x4;
      chunk.setBlockMetaData(getLocalCoords(wc), meta);
      sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc, b, meta));

      if (wY(wc) < 127 && chunk.blockType(getLocalCoords(wc + BLOCK_YPLUS)) == b)
      {
        uint8_t meta = chunk.getBlockMetaData(getLocalCoords(wc + BLOCK_YPLUS));
        meta ^= 0x4;
        chunk.setBlockMetaData(getLocalCoords(wc + BLOCK_YPLUS), meta);
        sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + BLOCK_YPLUS, b, meta));
      }

      if (wY(wc) > 0 && chunk.blockType(getLocalCoords(wc + BLOCK_YMINUS)) == b)
      {
        uint8_t meta = chunk.getBlockMetaData(getLocalCoords(wc + BLOCK_YMINUS));
        meta ^= 0x4;
        chunk.setBlockMetaData(getLocalCoords(wc + BLOCK_YMINUS), meta);
        sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + BLOCK_YMINUS, b, meta));
      }

      break;
    }
  default: break;
  }
}
예제 #6
0
GameStateManager::EBlockPlacement GameStateManager::blockPlacement(int32_t eid,
    const WorldCoords & wc, Direction dir, BlockItemInfoMap::const_iterator it, uint8_t & meta)
{
  // I believe we are never allowed to place anything on an already occupied block.
  // If that's false, we have to refactor this check. Water counts as unoccupied.

  if (!m_map.haveChunk(getChunkCoords(wc + dir)) || !isBuildable(EBlockItem(m_map.chunk(getChunkCoords(wc + dir)).blockType(getLocalCoords(wc + dir)))))
  {
    std::cout << "Sorry, cannot place object on occupied block at " << wc + dir << "." << std::endl;
    return CANNOT_PLACE;
  }

  // Likewise, we exclude globally right-clicks on banned block types, aka non-stackables.
  // Actually, I don't think the official server has such a rule. In fact, I think when the
  // client sends a PLACEMENT packet, it already expects the placement to be legal.
  // We're not expected to tell the client off. Oh well.

  if (!m_map.haveChunk(getChunkCoords(wc)) ||
      !isStackable(EBlockItem(m_map.chunk(getChunkCoords(wc)).blockType(getLocalCoords(wc)))) )
  {
    std::cout << "Sorry, cannot place object on non-stackable block at " << wc << "." << std::endl;
    return CANNOT_PLACE;
  }

  // Target block is clear and source block is stackable, let's get to work.

  switch(it->first) // block ID
  {
  case BLOCK_WoodenStairs:
  case BLOCK_CobblestoneStairs:
    {
      std::cout << "Special block: #" << eid << " is trying to place stairs." << std::endl;

      if (wY(wc) == 0 || dir == BLOCK_YMINUS) return CANNOT_PLACE;

      // Stairs are oriented to have their low end pointing toward the player.
      meta = 5 - int(m_states[eid]->getRelativeXZDirection(midpointRealCoords(wc + dir)));
      return OK_WITH_META;
    }

  case BLOCK_FurnaceBlock:
    {
      std::cout << "Special block: #" << eid << " is trying to place a furnace." << std::endl;

      if (wY(wc) == 0 || dir == BLOCK_YMINUS) return CANNOT_PLACE_AIRFORCE;

      const int d = int(m_states[eid]->getRelativeXZDirection(midpointRealCoords(wc + dir)));

      if      (d == 2) meta = 3;
      else if (d == 3) meta = 2;
      else if (d == 4) meta = 5;
      else if (d == 5) meta = 4;

      return OK_WITH_META;
    }
  case BLOCK_Torch:
  case BLOCK_RedstoneTorchOff:
  case BLOCK_RedstoneTorchOn:
    {
      std::cout << "Special block: #" << eid << " is trying to place a torch." << std::endl;

      // Torches are oriented simply to attach to the face which the user clicked.
      switch (int(dir))
      {
      case 2: meta = 4; break;
      case 3: meta = 3; break;
      case 4: meta = 2; break;
      case 5: meta = 1; break;
      default: meta = 5; break;
      }

      m_map.blockAlerts().insert(std::make_pair(wc, Map::BlockAlert(Map::BlockAlert::SUPPORTS_CANDLE)));

      return OK_WITH_META;
    }

  case ITEM_WoodenDoor:
  case ITEM_IronDoor:
    {
      // Doors can only be placed from above.
      if (dir != BLOCK_YPLUS)
        return CANNOT_PLACE;

      // Doors cannot be placed on glass, it seems.
      if (m_map.chunk(getChunkCoords(wc)).blockType(getLocalCoords(wc)) == BLOCK_Glass)
        return CANNOT_PLACE;

      const auto d = m_states[eid]->getRelativeXZDirection(midpointRealCoords(wc + dir));
      const unsigned char b = it->first == ITEM_WoodenDoor ? BLOCK_WoodenDoor : BLOCK_IronDoor;

      uint8_t meta;

      enum { HINGE_NE = 0, HINGE_SE = 1, HINGE_SW = 2, HINGE_NW = 3, SWUNG = 4 };

      switch (d)
      {
      case BLOCK_XPLUS:
        {
          if (m_map.haveChunk(getChunkCoords(wc + dir + BLOCK_ZPLUS)) &&
              !isBuildable(EBlockItem(m_map.chunk(getChunkCoords(wc + dir + BLOCK_ZPLUS)).blockType(getLocalCoords(wc + dir + BLOCK_ZPLUS)))))
            meta = HINGE_NW | SWUNG;
          else
            meta = HINGE_NE;
          break;
        }
      case BLOCK_XMINUS:
        {
          if (m_map.haveChunk(getChunkCoords(wc + dir + BLOCK_ZMINUS)) &&
              !isBuildable(EBlockItem(m_map.chunk(getChunkCoords(wc + dir + BLOCK_ZMINUS)).blockType(getLocalCoords(wc + dir + BLOCK_ZMINUS)))))
            meta = HINGE_SE | SWUNG;
          else
            meta = HINGE_SW;
          break;
        }
      case BLOCK_ZPLUS:
        {
          if (m_map.haveChunk(getChunkCoords(wc + dir + BLOCK_XMINUS)) &&
              !isBuildable(EBlockItem(m_map.chunk(getChunkCoords(wc + dir + BLOCK_XMINUS)).blockType(getLocalCoords(wc + dir + BLOCK_XMINUS)))))
            meta = HINGE_NE | SWUNG;
          else
            meta = HINGE_SE;
          break;
        }
      case BLOCK_ZMINUS:
        {
          if (m_map.haveChunk(getChunkCoords(wc + dir + BLOCK_XPLUS)) &&
              !isBuildable(EBlockItem(m_map.chunk(getChunkCoords(wc + dir + BLOCK_XPLUS)).blockType(getLocalCoords(wc + dir + BLOCK_XPLUS)))))
            meta = HINGE_SW | SWUNG;
          else
            meta = HINGE_NW;
          break;
        }
      default: return CANNOT_PLACE;
      }

      // Double-door algorithm: only check for a door on the left (apparently that's what the client does).
      if      (d == BLOCK_XMINUS && m_map.chunk(getChunkCoords(wc + dir + BLOCK_ZPLUS)) .blockType(getLocalCoords(wc + dir + BLOCK_ZPLUS))  == b)
      {
        meta = HINGE_SE | SWUNG;
      }
      else if (d == BLOCK_XPLUS  && m_map.chunk(getChunkCoords(wc + dir + BLOCK_ZMINUS)).blockType(getLocalCoords(wc + dir + BLOCK_ZMINUS)) == b)
      {
        meta = HINGE_NW | SWUNG;
      }
      else if (d == BLOCK_ZMINUS && m_map.chunk(getChunkCoords(wc + dir + BLOCK_XMINUS)).blockType(getLocalCoords(wc + dir + BLOCK_XMINUS)) == b)
      {
        meta = HINGE_SW | SWUNG;
      }
      else if (d == BLOCK_ZPLUS  && m_map.chunk(getChunkCoords(wc + dir + BLOCK_XPLUS)) .blockType(getLocalCoords(wc + dir + BLOCK_XPLUS))  == b)
      {
        meta = HINGE_NE | SWUNG;
      }

      sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + dir, b, meta));
      sendToAll(MAKE_CALLBACK(packetSCBlockChange, wc + dir + BLOCK_YPLUS, b, meta | 0x8));

      Chunk & chunk = m_map.chunk(getChunkCoords(wc + dir));
      chunk.blockType(getLocalCoords(wc + dir)) = b;
      chunk.setBlockMetaData(getLocalCoords(wc + dir), meta);
      chunk.blockType(getLocalCoords(wc + dir + BLOCK_YPLUS)) = b;
      chunk.setBlockMetaData(getLocalCoords(wc + dir + BLOCK_YPLUS), meta | 0x8);

      return OK_NO_META;
    }

  default:
    return OK_NO_META;
  }

  return OK_NO_META;
}