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; } }
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; }
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; }
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; } } } }
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; } }
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; }