Exemple #1
0
void hook_doAll(const char* hookID, ...)
{
  va_list argList;
  va_start(argList, hookID);
  runAllCallback(hookID,argList);
  va_end(argList);
}
Exemple #2
0
void Logger::log(LogType::LogType type, const std::string& source, const std::string& message)
{
	if (!ServerInstance->plugin()->hasHook("LogPost")) {
		std::clog.tie(&std::cout);
		if (type < LogType::LOG_WARNING) {
			std::clog.tie(&std::cerr);
		}

		std::clog << source << ": " << message << std::endl;
		return;
	}

	runAllCallback("LogPost",(int)type, source.c_str(), message.c_str());
}
Exemple #3
0
int PacketHandler::player_digging(User* user)
{
  int8_t status;
  int32_t x;
  int16_t  y;
  int8_t temp_y;
  int32_t z;
  int8_t direction;
  uint8_t block;
  uint8_t meta;
  BlockBasicPtr blockcb;
  BlockDefault blockD;

  user->buffer >> status >> x >> temp_y >> z >> direction;
  y = (uint8_t)temp_y;

  if (!user->buffer)
  {
    return PACKET_NEED_MORE_DATA;
  }

  user->buffer.removePacket();

  if (!ServerInstance->map(user->pos.map)->getBlock(x, y, z, &block, &meta))
  {
    blockD.revertBlock(user, x, y, z, user->pos.map);
    return PACKET_OK;
  }

  // Blocks that break with first hit
  if(status == BLOCK_STATUS_STARTED_DIGGING)
  {
      if( user->creative || (block == BLOCK_SNOW || block == BLOCK_REED || block == BLOCK_TORCH
                             || block == BLOCK_REDSTONE_WIRE || block == BLOCK_RED_ROSE || block == BLOCK_YELLOW_FLOWER
                             || block == BLOCK_BROWN_MUSHROOM || block == BLOCK_RED_MUSHROOM
                             || block == BLOCK_REDSTONE_TORCH_OFF || block == BLOCK_REDSTONE_TORCH_ON))
      {
          status = BLOCK_STATUS_BLOCK_BROKEN;
      }
  }

  switch (status)
  {
  case BLOCK_STATUS_STARTED_DIGGING:
  {
    runAllCallback("PlayerDiggingStarted",user->nick.c_str(), x, y, z, direction);

    for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
    {
      blockcb = ServerInstance->plugin()->getBlockCB()[i];
      if (blockcb != NULL && blockcb->affectedBlock(block))
      {
        blockcb->onStartedDigging(user, status, x, y, z, user->pos.map, direction);
      }
    }
    break;
  }

  case BLOCK_STATUS_BLOCK_BROKEN:
  {
    //Player tool usage calculation etc

    bool rightUse;
    int16_t itemSlot = user->currentItemSlot() + 36;
    int16_t itemHealth = ServerInstance->inventory()->itemHealth(user->inv[itemSlot].getType(), block, rightUse);
    if (itemHealth > 0)
    {
      user->inv[itemSlot].incHealth();
      if (!rightUse)
      {
        user->inv[itemSlot].incHealth();
      }

      if (itemHealth <= user->inv[itemSlot].getHealth())
      {
        user->inv[itemSlot].decCount();

        if (user->inv[itemSlot].getCount() == 0)
        {
          user->inv[itemSlot].setHealth(0);
          user->inv[itemSlot].setType(-1);
        }
      }
      ServerInstance->inventory()->setSlot(user, WINDOW_PLAYER, itemSlot, user->inv[itemSlot].getType(),
                                           user->inv[itemSlot].getCount(), user->inv[itemSlot].getHealth());
    }

    runCallbackUntilFalse("BlockBreakPre",user->nick.c_str(), x, y, z);
    if (callbackReturnValue)
    {
      blockD.revertBlock(user, x, y, z, user->pos.map);
      return PACKET_OK;
    }

    runAllCallback("BlockBreakPost",user->nick.c_str(), x, y, z);

    for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
    {
      blockcb = ServerInstance->plugin()->getBlockCB()[i];
      if (blockcb != NULL && blockcb->affectedBlock(block))
      {
        if (blockcb->onBroken(user, status, x, y, z, user->pos.map, direction))
        {
          // Do not break
          return PACKET_OK;
        }
        else
        {
          break;
        }
      }
    }

    /* notify neighbour blocks of the broken block */
    status = block;
    if (ServerInstance->map(user->pos.map)->getBlock(x + 1, y, z, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x + 1, y, z, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x + 1, y, z, user->pos.map, BLOCK_SOUTH);
        }
      }

    }

    if (ServerInstance->map(user->pos.map)->getBlock(x - 1, y, z, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x - 1, y, z, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x - 1, y, z, user->pos.map, BLOCK_NORTH);
        }
      }

    }

    if (ServerInstance->map(user->pos.map)->getBlock(x, y + 1, z, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x, y + 1, z, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x, y + 1, z, user->pos.map, BLOCK_TOP);
        }
      }

    }

    if (ServerInstance->map(user->pos.map)->getBlock(x, y - 1, z, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x, y - 1, z, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x, y - 1, z, user->pos.map, BLOCK_BOTTOM);
        }
      }

    }

    if (ServerInstance->map(user->pos.map)->getBlock(x, y, z + 1, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x, y, z + 1, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x, y, z + 1, user->pos.map, BLOCK_WEST);
        }
      }

    }

    if (ServerInstance->map(user->pos.map)->getBlock(x, y, z - 1, &block, &meta) && block != BLOCK_AIR)
    {
      runAllCallback("BlockNeighbourBreak",user->nick.c_str(), x, y, z - 1, x, int8_t(y), z);
      for (uint32_t i = 0 ; i < ServerInstance->plugin()->getBlockCB().size(); i++)
      {
        blockcb = ServerInstance->plugin()->getBlockCB()[i];
        if (blockcb != NULL && (blockcb->affectedBlock(status) || blockcb->affectedBlock(block)))
        {
          blockcb->onNeighbourBroken(user, status, x, y, z - 1, user->pos.map, BLOCK_EAST);
        }
      }

    }

    break;
  }
  case BLOCK_STATUS_PICKUP_SPAWN:
  {
    //ToDo: handle
#define itemSlot (36+user->currentItemSlot())
    if (user->inv[itemSlot].getType() > 0)
    {
      ServerInstance->map(user->pos.map)->createPickupSpawn(int(user->pos.x), int(user->pos.y), int(user->pos.z), int(user->inv[itemSlot].getType()), 1, int(user->inv[itemSlot].getHealth()), user);

      user->inv[itemSlot].decCount();
    }
    break;
#undef itemSlot
  }

  }

  return PACKET_OK;
}
Exemple #4
0
int PacketHandler::handshake(User* user)
{
  if (!user->buffer.haveData(9))
  {
    return PACKET_NEED_MORE_DATA;
  }

  std::string player, host;
  int8_t version;
  int32_t port;

  user->buffer >> version >> player >> host >> port;

  // Check for data
  if (!user->buffer)
  {
    return PACKET_NEED_MORE_DATA;
  }

  // Remove package from buffer
  user->buffer.removePacket();

  LOG(INFO, "Packets", "Player " + dtos(user->UID) + " login v." + dtos(version) + " : " + player);

  user->nick = player;

  // If version is not the current version
  if (version != PROTOCOL_VERSION)
  {
    user->kick(ServerInstance->config()->sData("strings.wrong_protocol"));
    return PACKET_OK;
  }

  // If userlimit is reached
  if ((int)User::all().size() > ServerInstance->config()->iData("system.user_limit"))
  {
    user->kick(ServerInstance->config()->sData("strings.server_full"));
    return PACKET_OK;
  }

  char* kickMessage = NULL;
  runCallbackUntilFalse("PlayerLoginPre",player.c_str(), &kickMessage);
  if (callbackReturnValue)
  {
    user->kick(std::string(kickMessage));
  }
  else
  {
    //We can skip the protocol encryption
    if(!ServerInstance->config()->bData("system.protocol_encryption"))
    {
      user->sendLoginInfo();
    }
    else
    {
      user->buffer << Protocol::encryptionRequest();
    }
    runAllCallback("PlayerLoginPost",player.c_str());
  }

  
  // TODO: Add support for prompting user for Server password

  return PACKET_OK;
}
bool Mineserver::run()
{
    uint32_t starttime = (uint32_t)time(0);
    uint32_t tick      = (uint32_t)time(0);


    // load plugins
    if (config()->has("system.plugins") && (config()->type("system.plugins") == CONFIG_NODE_LIST))
    {
        std::list<std::string> tmp = config()->mData("system.plugins")->keys();
        for (std::list<std::string>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
        {
            std::string path  = config()->sData("system.path.plugins");
            std::string name  = config()->sData("system.plugins." + (*it));
            std::string alias = *it;
            if (name[0] == '_')
            {
                path = "";
                alias = name;
                name = name.substr(1);
            }

            plugin()->loadPlugin(name, path, alias);
        }
    }

    // Initialize map
    for (int i = 0; i < (int)m_map.size(); i++)
    {
        physics(i)->enabled = (config()->bData("system.physics.enabled"));
        redstone(i)->enabled = (config()->bData("system.redstone.enabled"));

        m_map[i]->init(i);
        if (config()->bData("map.generate_spawn.enabled"))
        {
            LOG2(INFO, "Generating spawn area...");
            int size = config()->iData("map.generate_spawn.size");
            bool show_progress = config()->bData("map.generate_spawn.show_progress");
#ifdef __FreeBSD__
            show_progress = false;
#endif

#ifdef WIN32
            DWORD t_begin = 0, t_end = 0;
#else
            clock_t t_begin = 0, t_end = 0;
#endif

            for (int x = -size; x <= size; x++)
            {
                if (show_progress)
                {
#ifdef WIN32
                    t_begin = timeGetTime();
#else
                    t_begin = clock();
#endif
                }
                for (int z = -size; z <= size; z++)
                {
                    m_map[i]->loadMap(x, z);
                }

                if (show_progress)
                {
#ifdef WIN32
                    t_end = timeGetTime();
                    LOG2(INFO, dtos((x + size + 1) *(size * 2 + 1)) + "/" + dtos((size * 2 + 1) *(size * 2 + 1)) + " done. " + dtos((t_end - t_begin) / (size * 2 + 1)) + "ms per chunk");
#else
                    t_end = clock();
                    LOG2(INFO, dtos((x + size + 1) *(size * 2 + 1)) + "/" + dtos((size * 2 + 1) *(size * 2 + 1)) + " done. " + dtos(((t_end - t_begin) / (CLOCKS_PER_SEC / 1000)) / (size * 2 + 1)) + "ms per chunk");
#endif
                }
            }
        }
        // Choose proper spawn position
        m_map[i]->chooseSpawnPosition();
#ifdef DEBUG
        LOG(DEBUG, "Map", "Spawn area ready!");
#endif
    }

    // Initialize packethandler
    packetHandler()->init();

    // Load ip from config
    const std::string ip = config()->sData("net.ip");

    // Load port from config
    const int port = config()->iData("net.port");

#ifdef WIN32
    WSADATA wsaData;
    int iResult;
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0)
    {
        LOG2(ERROR, std::string("WSAStartup failed with error: " + iResult));
        return false;
    }
#endif

    struct sockaddr_in addresslisten;
    int reuse = 1;

    m_eventBase = reinterpret_cast<event_base*>(event_init());
#ifdef WIN32
    m_socketlisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#else
    m_socketlisten = socket(AF_INET, SOCK_STREAM, 0);
#endif

    if (m_socketlisten < 0)
    {
        LOG2(ERROR, "Failed to create listen socket");
        return false;
    }

    memset(&addresslisten, 0, sizeof(addresslisten));

    addresslisten.sin_family      = AF_INET;
    addresslisten.sin_addr.s_addr = inet_addr(ip.c_str());
    addresslisten.sin_port        = htons(port);

    //Reuse the socket
    setsockopt(m_socketlisten, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

    // Bind to port
    if (bind(m_socketlisten, (struct sockaddr*)&addresslisten, sizeof(addresslisten)) < 0)
    {
        LOG2(ERROR, "Failed to bind to " + ip + ":" + dtos(port));
        return false;
    }

    if (listen(m_socketlisten, 5) < 0)
    {
        LOG2(ERROR, "Failed to listen to socket");
        return false;
    }

    setnonblock(m_socketlisten);
    event_set(&m_listenEvent, m_socketlisten, EV_WRITE | EV_READ | EV_PERSIST, accept_callback, NULL);
    event_add(&m_listenEvent, NULL);

    LOG2(INFO, "Listening on: ");
    if (ip == "0.0.0.0")
    {
        // Print all local IPs
        char name[255];
        gethostname(name, sizeof(name));
        struct hostent* hostinfo = gethostbyname(name);
        int ipIndex = 0;
        while (hostinfo && hostinfo->h_addr_list[ipIndex])
        {
            const std::string ip(inet_ntoa(*(struct in_addr*)hostinfo->h_addr_list[ipIndex++]));
            LOG2(INFO, ip + ":" + dtos(port));
        }
    }
    else
    {
        LOG2(INFO, ip + ":" + dtos(port));
    }

    //Let event_base_loop lock for 200ms
    timeval loopTime;
    loopTime.tv_sec  = 0;
    loopTime.tv_usec = 200000; // 200ms

    m_running = true;
    event_base_loopexit(m_eventBase, &loopTime);

    // Create our Server Console user so we can issue commands

    time_t timeNow = time(NULL);
    while (m_running && event_base_loop(m_eventBase, 0) == 0)
    {
        event_base_loopexit(m_eventBase, &loopTime);

        // Run 200ms timer hook
        runAllCallback("Timer200");

        //Remove any users pending removal
        if(m_usersToRemove.size())
        {
            for (std::set<User*>::iterator it = m_usersToRemove.begin(); it != m_usersToRemove.end(); it++)
            {
                User* u = *it;
                delete u;
                u = 0;
            }
            m_usersToRemove.clear();
        }



        // Alert any block types that care about timers
        for (size_t i = 0 ; i < plugin()->getBlockCB().size(); ++i)
        {
            const BlockBasicPtr blockcb = plugin()->getBlockCB()[i];
            if (blockcb != NULL)
            {
                blockcb->timer200();
            }
        }

        //Update physics every 200ms
        for (std::vector<Map*>::size_type i = 0 ; i < m_map.size(); i++)
        {
            physics(i)->update();
            redstone(i)->update();
        }


        //Every 10 seconds..
        timeNow = time(0);
        if (timeNow - starttime > 10)
        {
            starttime = (uint32_t)timeNow;

            //Map saving on configurable interval
            if (m_saveInterval != 0 && timeNow - m_lastSave >= m_saveInterval)
            {
                //Save
                for (std::vector<Map*>::size_type i = 0; i < m_map.size(); i++)
                {
                    m_map[i]->saveWholeMap();
                }

                m_lastSave = timeNow;
            }

            // If users, ping them
            if (!User::all().empty())
            {
                // Send server time and keepalive
                Packet pkt;
                pkt << Protocol::timeUpdate(m_map[0]->mapTime);
                pkt << Protocol::keepalive(0);
                pkt << Protocol::playerlist();
                (*User::all().begin())->sendAll(pkt);
            }

            //Check for tree generation from saplings
            for (size_t i = 0; i < m_map.size(); ++i)
            {
                m_map[i]->checkGenTrees();
            }

            // TODO: Run garbage collection for chunk storage dealie?

            // Run 10s timer hook
            runAllCallback("Timer10000");
        }

        // Every second
        if (timeNow - tick > 0)
        {
            tick = (uint32_t)timeNow;
            std::set<User*> usersToRemove;
            // Loop users
            for (std::set<User*>::iterator it = m_users.begin(); it != m_users.end(); it++)
            {
                User * const & u = *it;

                // No data received in 30s, timeout
                if (u->logged && timeNow - u->lastData > 30)
                {
                    LOG2(INFO, "Player " + u->nick + " timed out");
                    usersToRemove.insert(u);

                }
                else if (!u->logged && timeNow - u->lastData > 100)
                {
                    usersToRemove.insert(u);
                }
                else
                {
                    if (m_damage_enabled)
                    {
                        u->checkEnvironmentDamage();
                    }
                    u->pushMap();
                    u->popMap();
                }
            }
            for (std::set<User*>::iterator it = usersToRemove.begin(); it != usersToRemove.end(); it++)
            {
                delete *it;
            }

            for (std::vector<Map*>::size_type i = 0 ; i < m_map.size(); i++)
            {
                m_map[i]->mapTime += 20;
                if (m_map[i]->mapTime >= 24000)
                {
                    m_map[i]->mapTime = 0;
                }
            }

            for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
            {
                (*it)->pushMap();
                (*it)->popMap();
            }

            // Check for Furnace activity
            furnaceManager()->update();

            // Check for user validation results
            pthread_mutex_lock(&ServerInstance->m_validation_mutex);
            for(size_t i = 0; i < ServerInstance->validatedUsers.size(); i++)
            {
                //To make sure user hasn't timed out or anything while validating
                User *tempuser = NULL;
                for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
                {
                    if((*it)->UID == ServerInstance->validatedUsers[i].UID)
                    {
                        tempuser = (*it);
                        break;
                    }
                }

                if(tempuser != NULL)
                {
                    if(ServerInstance->validatedUsers[i].valid)
                    {
                        LOG(INFO, "Packets", tempuser->nick + " is VALID ");
                        tempuser->crypted = true;
                        tempuser->buffer << (int8_t)PACKET_ENCRYPTION_RESPONSE << (int16_t)0 << (int16_t) 0;
                        tempuser->uncryptedLeft = 5;
                    }
                    else
                    {
                        tempuser->kick("User not Premium");
                    }
                    //Flush
                    client_write(tempuser);
                }
            }
            ServerInstance->validatedUsers.clear();
            pthread_mutex_unlock(&ServerInstance->m_validation_mutex);

            // Run 1s timer hook
            runAllCallback("Timer1000");
        }

        // Underwater check / drowning
        // ToDo: this could be done a bit differently? - Fador
        // -- User::all() == users() - louisdx


        for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
        {
            (*it)->isUnderwater();
            if ((*it)->pos.y < 0)
            {
                (*it)->sethealth((*it)->health - 5);
            }
            //Flush data
            client_write((*it));
        }
    }
#ifdef WIN32
    closesocket(m_socketlisten);
#else
    close(m_socketlisten);
#endif

    saveAll();

    event_base_free(m_eventBase);

    return true;
}