Exemple #1
0
void Raids::checkRaids()
{
    if (!getRunning()) {
        uint64_t now = OTSYS_TIME();

        for (auto it = raidList.begin(), end = raidList.end(); it != end; ++it) {
            Raid* raid = *it;
            if (now >= (getLastRaidEnd() + raid->getMargin())) {
                if (((MAX_RAND_RANGE * CHECK_RAIDS_INTERVAL) / raid->getInterval()) >= static_cast<uint32_t>(uniform_random(0, MAX_RAND_RANGE))) {
                    setRunning(raid);
                    raid->startRaid();

                    if (!raid->canBeRepeated()) {
                        raidList.erase(it);
                    }
                    break;
                }
            }
        }
    }

    checkRaidsEvent = g_scheduler.addEvent(createSchedulerTask(CHECK_RAIDS_INTERVAL * 1000, std::bind(&Raids::checkRaids, this)));
}
Exemple #2
0
bool Actions::useItem(Player* player, const Position& pos, uint8_t index, Item* item, bool isHotkey)
{
	if (!player->canDoAction()) {
		return false;
	}

	player->setNextActionTask(nullptr);
	player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::ACTIONS_DELAY_INTERVAL));
	player->stopWalk();

	if (isHotkey) {
		showUseHotkeyMessage(player, item->getID(), player->__getItemTypeCount(item->getID(), -1));
	}

	ReturnValue ret = internalUseItem(player, pos, index, item, 0);

	if (ret != RET_NOERROR) {
		player->sendCancelMessage(ret);
		return false;
	}

	return true;
}
Exemple #3
0
bool Ban::acceptConnection(uint32_t clientip)
{
	std::lock_guard<std::recursive_mutex> lockClass(lock);

	uint64_t currentTime = OTSYS_TIME();

	auto it = ipConnectMap.find(clientip);
	if (it == ipConnectMap.end()) {
		ConnectBlock cb;
		cb.lastAttempt = currentTime;
		cb.blockTime = 0;
		cb.count = 1;
		ipConnectMap[clientip] = cb;
		return true;
	}

	ConnectBlock& connectBlock = it->second;
	if (connectBlock.blockTime > currentTime) {
		connectBlock.blockTime += 250;
		return false;
	}

	int64_t timeDiff = currentTime - connectBlock.lastAttempt;
	connectBlock.lastAttempt = currentTime;
	if (timeDiff <= 5000) {
		if (++connectBlock.count > 5) {
			connectBlock.count = 0;
			if (timeDiff <= 500) {
				connectBlock.blockTime = currentTime + 3000;
				return false;
			}
		}
	} else {
		connectBlock.count = 1;
	}
	return true;
}
Exemple #4
0
bool Party::canUseSharedExperience(const Player* player) const
{
	uint32_t highestLevel = getLeader()->getLevel();
	for(PlayerVector::const_iterator it = memberList.begin(); it != memberList.end(); ++it){
		if( (*it)->getLevel() > highestLevel){
			highestLevel = (*it)->getLevel();
		}
	}

	uint32_t minLevel = (int32_t)std::ceil(((float)(highestLevel) * 2) / 3);
	if(player->getLevel() < minLevel){
		return false;
	}

	const Position& leaderPos = getLeader()->getPosition();
	const Position& memberPos = player->getPosition();

	if(!Position::areInRange<30,30,1>(leaderPos, memberPos)){
		return false;
	}

	if(!player->hasFlag(PlayerFlag_NotGainInFight)){
		//check if the player has healed/attacked anything recently
		CountMap::const_iterator it = pointMap.find(player->getID());
		if(it == pointMap.end()){
			return false;
		}

		uint64_t timeDiff = OTSYS_TIME() - it->second.ticks;
		if(timeDiff > g_game.getInFightTicks()){
			//player has not attacked or healed anyone for a period of infight ticks
			return false;
		}
	}

	return true;
}
Exemple #5
0
void MagicField::onStepInField(const CreatureP& creature)
{
	if(getId() == ITEM_MAGICWALL_SAFE || getId() == ITEM_WILDGROWTH_SAFE || isBlocking(creature.get()))
	{
		if(!creature->isGhost())
			server.game().internalRemoveItem(creature.get(), this, 1);

		return;
	}

	if(!getKind()->condition)
		return;

	Condition* condition = getKind()->condition->clone();
	uint32_t ownerId = getOwner();
	if(ownerId && !getTile()->hasFlag(TILESTATE_PVPZONE))
	{
		if(auto owner = server.world().getCreatureById(ownerId))
		{
			bool harmful = true;
			if((server.game().getWorldType() == WORLD_TYPE_NO_PVP || getTile()->hasFlag(TILESTATE_NOPVPZONE))
				&& (owner->getPlayer() || owner->hasController()))
				harmful = false;
			else if(Player* targetPlayer = creature->getPlayer())
			{
				if(owner->getPlayer() && Combat::isProtected(owner->getPlayer(), targetPlayer))
					harmful = false;
			}

			if(!harmful || (OTSYS_TIME() - createTime) <= (uint32_t)server.configManager().getNumber(
				ConfigManager::FIELD_OWNERSHIP) || creature->hasBeenAttacked(ownerId))
				condition->setParam(CONDITIONPARAM_OWNER, ownerId);
		}
	}

	creature->addCondition(condition);
}
Exemple #6
0
void Creature::onWalk(Direction& dir)
{
	int32_t drunk = -1;
	if(!isSuppress(CONDITION_DRUNK))
	{
		Condition* condition = NULL;
		for(ConditionList::const_iterator it = conditions.begin(); it != conditions.end(); ++it)
		{
			if(!(condition = *it) || condition->getType() != CONDITION_DRUNK)
				continue;

			int32_t subId = condition->getSubId();
			if((!condition->getEndTime() || condition->getEndTime() >= OTSYS_TIME()) && subId > drunk)
				drunk = subId;
		}
	}

	if(drunk < 0)
		return;

	drunk += 25;
	int32_t r = random_range(1, 100);
	if(r > drunk)
		return;

	int32_t tmp = (drunk / 5);
	if(r <= tmp)
		dir = NORTH;
	else if(r <= (tmp * 2))
		dir = WEST;
	else if(r <= (tmp * 3))
		dir = SOUTH;
	else if(r <= (tmp * 4))
		dir = EAST;

	g_game.internalCreatureSay(this, MSG_SPEAK_MONSTER_SAY, "Hicks!", isGhost());
}
Exemple #7
0
bool Party::canUseSharedExperience(const Player* player) const
{
	if (memberList.empty()) {
		return false;
	}

	uint32_t highestLevel = leader->getLevel();
	for (Player* member : memberList) {
		if (member->getLevel() > highestLevel) {
			highestLevel = member->getLevel();
		}
	}

	uint32_t minLevel = static_cast<int32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
	if (player->getLevel() < minLevel) {
		return false;
	}

	if (!Position::areInRange<30, 30, 1>(leader->getPosition(), player->getPosition())) {
		return false;
	}

	if (!player->hasFlag(PlayerFlag_NotGainInFight)) {
		//check if the player has healed/attacked anything recently
		auto it = ticksMap.find(player->getID());
		if (it == ticksMap.end()) {
			return false;
		}

		uint64_t timeDiff = OTSYS_TIME() - it->second;
		if (timeDiff > static_cast<uint64_t>(g_config.getNumber(ConfigManager::PZ_LOCKED))) {
			return false;
		}
	}
	return true;
}
Exemple #8
0
void Spawn::cleanup()
{
	Monster* monster;
	uint32_t spawnId;

	for (SpawnedMap::iterator it = spawnedMap.begin(); it != spawnedMap.end();) {
		spawnId = it->first;
		monster = it->second;

		if (monster->isRemoved()) {
			if (spawnId != 0) {
				spawnMap[spawnId].lastSpawn = OTSYS_TIME();
			}

			monster->releaseThing2();
			spawnedMap.erase(it++);
		} else if (!isInSpawnZone(monster->getPosition()) && spawnId != 0) {
			spawnedMap.insert(spawned_pair(0, monster));
			spawnedMap.erase(it++);
		} else {
			++it;
		}
	}
}
Exemple #9
0
bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup /*= false*/)
{
	std::unique_ptr<Monster> monster_ptr(new Monster(mType));
	if (startup) {
		//No need to send out events to the surrounding since there is no one out there to listen!
		if (!g_game.internalPlaceCreature(monster_ptr.get(), pos, true)) {
			return false;
		}
	} else {
		if (!g_game.placeCreature(monster_ptr.get(), pos, false, true)) {
			return false;
		}
	}

	Monster* monster = monster_ptr.release();
	monster->setDirection(dir);
	monster->setSpawn(this);
	monster->setMasterPos(pos);
	monster->incrementReferenceCounter();

	spawnedMap.insert(spawned_pair(spawnId, monster));
	spawnMap[spawnId].lastSpawn = OTSYS_TIME();
	return true;
}
Exemple #10
0
void Raids::checkRaids()
{
	if(!getRunning())
	{
		uint64_t now = OTSYS_TIME();
		for(RaidList::iterator it = raidList.begin(); it != raidList.end(); ++it)
		{
			if(now >= (getLastRaidEnd() + (*it)->getMargin()))
			{
				if(MAX_RAND_RANGE*CHECK_RAIDS_INTERVAL/(*it)->getInterval() >= (uint32_t)random_range(0, MAX_RAND_RANGE))
				{
					#ifdef __DEBUG_RAID__
					std::cout << formatDate(time(NULL)) << " [Notice] Raids: Starting raid " << (*it)->getName() << std::endl;
					#endif
					setRunning(*it);
					(*it)->startRaid();
					break;
				}
			}

		}
	}
	checkRaidsEvent = g_scheduler.addEvent(createSchedulerTask(CHECK_RAIDS_INTERVAL * 1000, boost::bind(&Raids::checkRaids, this)));
}
void ProtocolStatus::sendStatusString()
{
	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (!output) {
		getConnection()->close();
		return;
	}

	setRawMessages(true);

	pugi::xml_document doc;

	pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
	decl.append_attribute("version") = "1.0";

	pugi::xml_node tsqp = doc.append_child("tsqp");
	tsqp.append_attribute("version") = "1.0";

	pugi::xml_node serverinfo = tsqp.append_child("serverinfo");
	uint64_t uptime = (OTSYS_TIME() - ProtocolStatus::start) / 1000;
	serverinfo.append_attribute("uptime") = std::to_string(uptime).c_str();
	serverinfo.append_attribute("ip") = g_config.getString(ConfigManager::IP).c_str();
	serverinfo.append_attribute("servername") = g_config.getString(ConfigManager::SERVER_NAME).c_str();
	serverinfo.append_attribute("port") = std::to_string(g_config.getNumber(ConfigManager::LOGIN_PORT)).c_str();
	serverinfo.append_attribute("location") = g_config.getString(ConfigManager::LOCATION).c_str();
	serverinfo.append_attribute("url") = g_config.getString(ConfigManager::URL).c_str();
	serverinfo.append_attribute("server") = STATUS_SERVER_NAME;
	serverinfo.append_attribute("version") = STATUS_SERVER_VERSION;
	serverinfo.append_attribute("client") = CLIENT_VERSION_STR;

	pugi::xml_node owner = tsqp.append_child("owner");
	owner.append_attribute("name") = g_config.getString(ConfigManager::OWNER_NAME).c_str();
	owner.append_attribute("email") = g_config.getString(ConfigManager::OWNER_EMAIL).c_str();

	pugi::xml_node players = tsqp.append_child("players");
	players.append_attribute("online") = std::to_string(g_game.getPlayersOnline()).c_str();
	players.append_attribute("max") = std::to_string(g_config.getNumber(ConfigManager::MAX_PLAYERS)).c_str();
	players.append_attribute("peak") = std::to_string(g_game.getPlayersRecord()).c_str();

	pugi::xml_node monsters = tsqp.append_child("monsters");
	monsters.append_attribute("total") = std::to_string(g_game.getMonstersOnline()).c_str();

	pugi::xml_node npcs = tsqp.append_child("npcs");
	npcs.append_attribute("total") = std::to_string(g_game.getNpcsOnline()).c_str();

	pugi::xml_node rates = tsqp.append_child("rates");
	rates.append_attribute("experience") = std::to_string(g_config.getNumber(ConfigManager::RATE_EXPERIENCE)).c_str();
	rates.append_attribute("skill") = std::to_string(g_config.getNumber(ConfigManager::RATE_SKILL)).c_str();
	rates.append_attribute("loot") = std::to_string(g_config.getNumber(ConfigManager::RATE_LOOT)).c_str();
	rates.append_attribute("magic") = std::to_string(g_config.getNumber(ConfigManager::RATE_MAGIC)).c_str();
	rates.append_attribute("spawn") = std::to_string(g_config.getNumber(ConfigManager::RATE_SPAWN)).c_str();

	pugi::xml_node map = tsqp.append_child("map");
	map.append_attribute("name") = g_config.getString(ConfigManager::MAP_NAME).c_str();
	map.append_attribute("author") = g_config.getString(ConfigManager::MAP_AUTHOR).c_str();

	uint32_t mapWidth, mapHeight;
	g_game.getMapDimensions(mapWidth, mapHeight);
	map.append_attribute("width") = std::to_string(mapWidth).c_str();
	map.append_attribute("height") = std::to_string(mapHeight).c_str();

	pugi::xml_node motd = tsqp.append_child("motd");
	motd.text() = g_config.getString(ConfigManager::MOTD).c_str();

	std::ostringstream ss;
	doc.save(ss, "", pugi::format_raw);

	std::string data = ss.str();
	output->addBytes(data.c_str(), data.size());
	OutputMessagePool::getInstance()->send(output);
	getConnection()->close();
}
void ProtocolStatus::sendInfo(uint16_t requestedInfo, const std::string& characterName)
{
	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (!output) {
		getConnection()->close();
		return;
	}

	if (requestedInfo & REQUEST_BASIC_SERVER_INFO) {
		output->addByte(0x10);
		output->addString(g_config.getString(ConfigManager::SERVER_NAME));
		output->addString(g_config.getString(ConfigManager::IP));
		output->addString(std::to_string(g_config.getNumber(ConfigManager::LOGIN_PORT)));
	}

	if (requestedInfo & REQUEST_OWNER_SERVER_INFO) {
		output->addByte(0x11);
		output->addString(g_config.getString(ConfigManager::OWNER_NAME));
		output->addString(g_config.getString(ConfigManager::OWNER_EMAIL));
	}

	if (requestedInfo & REQUEST_MISC_SERVER_INFO) {
		output->addByte(0x12);
		output->addString(g_config.getString(ConfigManager::MOTD));
		output->addString(g_config.getString(ConfigManager::LOCATION));
		output->addString(g_config.getString(ConfigManager::URL));
		output->add<uint64_t>((OTSYS_TIME() - ProtocolStatus::start) / 1000);
	}

	if (requestedInfo & REQUEST_PLAYERS_INFO) {
		output->addByte(0x20);
		output->add<uint32_t>(g_game.getPlayersOnline());
		output->add<uint32_t>(g_config.getNumber(ConfigManager::MAX_PLAYERS));
		output->add<uint32_t>(g_game.getPlayersRecord());
	}

	if (requestedInfo & REQUEST_MAP_INFO) {
		output->addByte(0x30);
		output->addString(g_config.getString(ConfigManager::MAP_NAME));
		output->addString(g_config.getString(ConfigManager::MAP_AUTHOR));
		uint32_t mapWidth, mapHeight;
		g_game.getMapDimensions(mapWidth, mapHeight);
		output->add<uint16_t>(mapWidth);
		output->add<uint16_t>(mapHeight);
	}

	if (requestedInfo & REQUEST_EXT_PLAYERS_INFO) {
		output->addByte(0x21); // players info - online players list

		const auto& players = g_game.getPlayers();
		output->add<uint32_t>(players.size());
		for (const auto& it : players) {
			output->addString(it.second->getName());
			output->add<uint32_t>(it.second->getLevel());
		}
	}

	if (requestedInfo & REQUEST_PLAYER_STATUS_INFO) {
		output->addByte(0x22); // players info - online status info of a player
		if (g_game.getPlayerByName(characterName) != nullptr) {
			output->addByte(0x01);
		} else {
			output->addByte(0x00);
		}
	}

	if (requestedInfo & REQUEST_SERVER_SOFTWARE_INFO) {
		output->addByte(0x23); // server software info
		output->addString(STATUS_SERVER_NAME);
		output->addString(STATUS_SERVER_VERSION);
		output->addString(CLIENT_VERSION_STR);
	}
	OutputMessagePool::getInstance()->send(output);
	getConnection()->close();
}
#include "otpch.h"

#include "protocolstatus.h"
#include "configmanager.h"
#include "game.h"
#include "connection.h"
#include "networkmessage.h"
#include "outputmessage.h"
#include "tools.h"
#include "tasks.h"

extern ConfigManager g_config;
extern Game g_game;

std::map<uint32_t, int64_t> ProtocolStatus::ipConnectMap;
const uint64_t ProtocolStatus::start = OTSYS_TIME();

enum RequestedInfo_t : uint16_t {
	REQUEST_BASIC_SERVER_INFO = 1 << 0,
	REQUEST_OWNER_SERVER_INFO = 1 << 1,
	REQUEST_MISC_SERVER_INFO = 1 << 2,
	REQUEST_PLAYERS_INFO = 1 << 3,
	REQUEST_MAP_INFO = 1 << 4,
	REQUEST_EXT_PLAYERS_INFO = 1 << 5,
	REQUEST_PLAYER_STATUS_INFO = 1 << 6,
	REQUEST_SERVER_SOFTWARE_INFO = 1 << 7,
};

void ProtocolStatus::onRecvFirstMessage(NetworkMessage& msg)
{
	uint32_t ip = getIP();
void Creature::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
                              const Tile* oldTile, const Position& oldPos, bool teleport)
{
	if (creature == this) {
		lastStep = OTSYS_TIME();
		lastStepCost = 1;

		if (!teleport) {
			if (oldPos.z != newPos.z) {
				//floor change extra cost
				lastStepCost = 2;
			} else if (Position::getDistanceX(newPos, oldPos) >= 1 && Position::getDistanceY(newPos, oldPos) >= 1) {
				//diagonal extra cost
				lastStepCost = 2;
			}
		} else {
			stopEventWalk();
		}

		if (!summons.empty()) {
			//check if any of our summons is out of range (+/- 2 floors or 30 tiles away)
			std::list<Creature*> despawnList;
			std::list<Creature*>::iterator cit;

			for (cit = summons.begin(); cit != summons.end(); ++cit) {
				const Position pos = (*cit)->getPosition();
				if (Position::getDistanceZ(newPos, pos) > 2 || (std::max<int32_t>(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30)) {
					despawnList.push_back((*cit));
				}
			}

			for (cit = despawnList.begin(); cit != despawnList.end(); ++cit) {
				g_game.removeCreature((*cit), true);
			}
		}

		if (newTile->getZone() != oldTile->getZone()) {
			onChangeZone(getZone());
		}

		//update map cache
		if (isMapLoaded) {
			if (teleport || oldPos.z != newPos.z) {
				updateMapCache();
			} else {
				Tile* tile;
				const Position& myPos = getPosition();
				Position pos;

				if (oldPos.y > newPos.y) { //north
					//shift y south
					for (int32_t y = mapWalkHeight - 1 - 1; y >= 0; --y) {
						memcpy(localMapCache[y + 1], localMapCache[y], sizeof(localMapCache[y]));
					}

					//update 0
					for (int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x) {
						tile = g_game.getTile(myPos.getX() + x, myPos.getY() - ((mapWalkHeight - 1) / 2), myPos.z);
						updateTileCache(tile, x, -((mapWalkHeight - 1) / 2));
					}
				} else if (oldPos.y < newPos.y) { // south
					//shift y north
					for (int32_t y = 0; y <= mapWalkHeight - 1 - 1; ++y) {
						memcpy(localMapCache[y], localMapCache[y + 1], sizeof(localMapCache[y]));
					}

					//update mapWalkHeight - 1
					for (int32_t x = -((mapWalkWidth - 1) / 2); x <= ((mapWalkWidth - 1) / 2); ++x) {
						tile = g_game.getTile(myPos.getX() + x, myPos.getY() + ((mapWalkHeight - 1) / 2), myPos.z);
						updateTileCache(tile, x, (mapWalkHeight - 1) / 2);
					}
				}

				if (oldPos.x < newPos.x) { // east
					//shift y west
					int32_t starty = 0;
					int32_t endy = mapWalkHeight - 1;
					int32_t dy = Position::getDistanceY(oldPos, newPos);

					if (dy < 0) {
						endy += dy;
					} else if (dy > 0) {
						starty = dy;
					}

					for (int32_t y = starty; y <= endy; ++y) {
						for (int32_t x = 0; x <= mapWalkWidth - 2; ++x) {
							localMapCache[y][x] = localMapCache[y][x + 1];
						}
					}

					//update mapWalkWidth - 1
					for (int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y) {
						tile = g_game.getTile(myPos.x + ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z);
						updateTileCache(tile, (mapWalkWidth - 1) / 2, y);
					}
				} else if (oldPos.x > newPos.x) { // west
					//shift y east
					int32_t starty = 0;
					int32_t endy = mapWalkHeight - 1;
					int32_t dy = Position::getDistanceY(oldPos, newPos);

					if (dy < 0) {
						endy += dy;
					} else if (dy > 0) {
						starty = dy;
					}

					for (int32_t y = starty; y <= endy; ++y) {
						for (int32_t x = mapWalkWidth - 2; x >= 0; --x) {
							localMapCache[y][x + 1] = localMapCache[y][x];
						}
					}

					//update 0
					for (int32_t y = -((mapWalkHeight - 1) / 2); y <= ((mapWalkHeight - 1) / 2); ++y) {
						tile = g_game.getTile(myPos.x - ((mapWalkWidth - 1) / 2), myPos.y + y, myPos.z);
						updateTileCache(tile, -((mapWalkWidth - 1) / 2), y);
					}
				}

				updateTileCache(oldTile, oldPos);
			}
		}
	} else {
		if (isMapLoaded) {
			const Position& myPos = getPosition();

			if (newPos.z == myPos.z) {
				updateTileCache(newTile, newPos);
			}

			if (oldPos.z == myPos.z) {
				updateTileCache(oldTile, oldPos);
			}
		}
	}

	if (creature == followCreature || (creature == this && followCreature)) {
		if (hasFollowPath) {
			isUpdatingPath = true;
		}

		if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) {
			onCreatureDisappear(followCreature, false);
		}
	}

	if (creature == attackedCreature || (creature == this && attackedCreature)) {
		if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) {
			onCreatureDisappear(attackedCreature, false);
		} else {
			if (hasExtraSwing()) {
				//our target is moving lets see if we can get in hit
				g_dispatcher.addTask(createTask(boost::bind(&Game::checkCreatureAttack, &g_game, getID())));
			}

			if (newTile->getZone() != oldTile->getZone()) {
				onAttackedCreatureChangeZone(attackedCreature->getZone());
			}
		}
	}
}
bool GlobalEvent::configureEvent(const pugi::xml_node& node)
{
	pugi::xml_attribute nameAttribute = node.attribute("name");
	if (!nameAttribute) {
		std::cout << "[Error - GlobalEvent::configureEvent] Missing name for a globalevent" << std::endl;
		return false;
	}

	name = nameAttribute.as_string();
	eventType = GLOBALEVENT_NONE;

	pugi::xml_attribute attr;
	if ((attr = node.attribute("time"))) {
		std::vector<int32_t> params = vectorAtoi(explodeString(attr.as_string(), ":"));

		int32_t hour = params.front();
		if (hour < 0 || hour > 23) {
			std::cout << "[Error - GlobalEvent::configureEvent] Invalid hour \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
			return false;
		}

		interval |= hour << 16;

		int32_t min = 0;
		int32_t sec = 0;
		if (params.size() > 1) {
			min = params[1];
			if (min < 0 || min > 59) {
				std::cout << "[Error - GlobalEvent::configureEvent] Invalid minute \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
				return false;
			}

			if (params.size() > 2) {
				sec = params[2];
				if (sec < 0 || sec > 59) {
					std::cout << "[Error - GlobalEvent::configureEvent] Invalid second \"" << attr.as_string() << "\" for globalevent with name: " << name << std::endl;
					return false;
				}
			}
		}

		time_t current_time = time(nullptr);
		tm* timeinfo = localtime(&current_time);
		timeinfo->tm_hour = hour;
		timeinfo->tm_min = min;
		timeinfo->tm_sec = sec;

		time_t difference = static_cast<time_t>(difftime(mktime(timeinfo), current_time));
		if (difference < 0) {
			difference += 86400;
		}

		nextExecution = current_time + difference;
		eventType = GLOBALEVENT_TIMER;
	} else if ((attr = node.attribute("type"))) {
		const char* value = attr.value();
		if (strcasecmp(value, "startup") == 0) {
			eventType = GLOBALEVENT_STARTUP;
		} else if (strcasecmp(value, "shutdown") == 0) {
			eventType = GLOBALEVENT_SHUTDOWN;
		} else if (strcasecmp(value, "record") == 0) {
			eventType = GLOBALEVENT_RECORD;
		} else {
			std::cout << "[Error - GlobalEvent::configureEvent] No valid type \"" << attr.as_string() << "\" for globalevent with name " << name << std::endl;
			return false;
		}
	} else if ((attr = node.attribute("interval"))) {
		interval = std::max<int32_t>(SCHEDULER_MINTICKS, pugi::cast<int32_t>(attr.value()));
		nextExecution = OTSYS_TIME() + interval;
	} else {
		std::cout << "[Error - GlobalEvent::configureEvent] No interval for globalevent with name " << name << std::endl;
		return false;
	}
	return true;
}
Exemple #16
0
void Creature::onDeath()
{
	bool lastHitUnjustified = false;
	bool mostDamageUnjustified = false;
	Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
	Creature* lastHitCreatureMaster;
	if (lastHitCreature) {
		lastHitUnjustified = lastHitCreature->onKilledCreature(this);
		lastHitCreatureMaster = lastHitCreature->getMaster();
	} else {
		lastHitCreatureMaster = nullptr;
	}

	Creature* mostDamageCreature = nullptr;

	const int64_t timeNow = OTSYS_TIME();
	const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
	int32_t mostDamage = 0;
	std::map<Creature*, uint64_t> experienceMap;
	for (const auto& it : damageMap) {
		if (Creature* attacker = g_game.getCreatureByID(it.first)) {
			CountBlock_t cb = it.second;
			if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
				mostDamage = cb.total;
				mostDamageCreature = attacker;
			}

			if (attacker != this) {
				uint64_t gainExp = getGainedExperience(attacker);
				if (Player* player = attacker->getPlayer()) {
					Party* party = player->getParty();
					if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
						attacker = party->getLeader();
					}
				}

				auto tmpIt = experienceMap.find(attacker);
				if (tmpIt == experienceMap.end()) {
					experienceMap[attacker] = gainExp;
				} else {
					tmpIt->second += gainExp;
				}
			}
		}
	}

	for (const auto& it : experienceMap) {
		it.first->onGainExperience(it.second, this);
	}

	if (mostDamageCreature) {
		if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
			Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
			if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
				mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
			}
		}
	}

	bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
	death(lastHitCreature);

	if (master) {
		master->removeSummon(this);
	}

	if (droppedCorpse) {
		g_game.removeCreature(this, false);
	}
}
void Condition::setTicks(int32_t _ticks)
{
	ticks = _ticks;
	if(_ticks > 0)
		endTime = OTSYS_TIME() + _ticks;
}
Exemple #18
0
void Dispatcher::dispatcherThread(void* p)
{
	#if defined __EXCEPTION_TRACER__
	ExceptionHandler dispatcherExceptionHandler;
	dispatcherExceptionHandler.InstallHandler();
	#endif
	srand((unsigned int)OTSYS_TIME());
	#ifdef __DEBUG_SCHEDULER__
	std::cout << "Starting Dispatcher" << std::endl;
	#endif

	OutputMessagePool* outputPool;

	// NOTE: second argument defer_lock is to prevent from immediate locking
	boost::unique_lock<boost::mutex> taskLockUnique(getDispatcher().m_taskLock, boost::defer_lock);

	while(Dispatcher::m_threadState != Dispatcher::STATE_TERMINATED){
		Task* task = NULL;

		// check if there are tasks waiting
		taskLockUnique.lock();//getDispatcher().m_taskLock.lock();

		if(getDispatcher().m_taskList.empty()){
			//if the list is empty wait for signal
			#ifdef __DEBUG_SCHEDULER__
			std::cout << "Dispatcher: Waiting for task" << std::endl;
			#endif
			getDispatcher().m_taskSignal.wait(taskLockUnique);
		}

		#ifdef __DEBUG_SCHEDULER__
		std::cout << "Dispatcher: Signalled" << std::endl;
		#endif

		if(!getDispatcher().m_taskList.empty() && (Dispatcher::m_threadState != Dispatcher::STATE_TERMINATED)){
			// take the first task
			task = getDispatcher().m_taskList.front();
			getDispatcher().m_taskList.pop_front();
		}

		taskLockUnique.unlock();

		// finally execute the task...
		if(task){
			OutputMessagePool::getInstance()->startExecutionFrame();
			(*task)();
			delete task;
			
			outputPool = OutputMessagePool::getInstance();
			if(outputPool){
				outputPool->sendAll();
			}

			g_game.clearSpectatorCache();
			#ifdef __DEBUG_SCHEDULER__
			std::cout << "Dispatcher: Executing task" << std::endl;
			#endif
		}
	}
#if defined __EXCEPTION_TRACER__
	dispatcherExceptionHandler.RemoveHandler();
#endif
}
Exemple #19
0
int main(int argc, char *argv[])
{
	std::srand((uint32_t)OTSYS_TIME());
	StringVec args = StringVec(argv, argv + argc);
	if(argc > 1 && !argumentsHandler(args))
		return 0;

#else
void serverMain(void* param)
{
	std::cout.rdbuf(&g_logger);
	std::cerr.rdbuf(&g_logger);
	std::clog.rdbuf(&g_logger);

#endif
	std::set_new_handler(allocationHandler);
	ServiceManager servicer;
	g_config.startup();

#ifdef __OTSERV_ALLOCATOR_STATS__
	//boost::thread(boost::bind(&allocatorStatsThread, (void*)NULL));
	// TODO: this thread needs a shutdown (timed_lock + interrupt? .interrupt + .unlock)
#endif
#ifdef __EXCEPTION_TRACER__
	ExceptionHandler mainExceptionHandler;
	mainExceptionHandler.InstallHandler();
#endif
#ifndef WINDOWS

	// ignore sigpipe...
	struct sigaction sigh;
	sigh.sa_handler = SIG_IGN;
	sigh.sa_flags = 0;

	sigemptyset(&sigh.sa_mask);
	sigaction(SIGPIPE, &sigh, NULL);

	// register signals
	signal(SIGHUP, signalHandler); //save
	signal(SIGTRAP, signalHandler); //clean
	signal(SIGCHLD, signalHandler); //refresh
	signal(SIGUSR1, signalHandler); //close server
	signal(SIGUSR2, signalHandler); //open server
	signal(SIGCONT, signalHandler); //reload all
	signal(SIGQUIT, signalHandler); //save & shutdown
	signal(SIGTERM, signalHandler); //shutdown
#endif

	Dispatcher::getInstance().addTask(createTask(boost::bind(otserv,
	#if !defined(WINDOWS) || defined(_CONSOLE)
	args,
	#endif
	&servicer)));
	g_loaderSignal.wait(g_loaderUniqueLock);

	boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
	if(servicer.isRunning())
	{
		Status::getInstance();
		std::clog << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " server Online!" << std::endl << std::endl;
		#if defined(WINDOWS) && !defined(_CONSOLE)
		SendMessage(GUI::getInstance()->m_statusBar, WM_SETTEXT, 0, (LPARAM)">> server Online!");
		GUI::getInstance()->m_connections = true;
		#endif
		servicer.run();
	}
	else
	{
		Status::getInstance();
		std::clog << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " server Offline! No services available..." << std::endl << std::endl;
		#if defined(WINDOWS) && !defined(_CONSOLE)
		SendMessage(GUI::getInstance()->m_statusBar, WM_SETTEXT, 0, (LPARAM)">> server Offline! No services available...");
		GUI::getInstance()->m_connections = true;
		#endif
	}

	Dispatcher::getInstance().exit();
	Scheduler::getInstance().exit();

#ifdef __EXCEPTION_TRACER__
	mainExceptionHandler.RemoveHandler();
#endif
#if !defined(WINDOWS) || defined(_CONSOLE)
	return 0;
#endif
}
Exemple #20
0
void mainLoader(int, char*[], ServiceManager* services)
{
    //dispatcher thread
    g_game.setGameState(GAME_STATE_STARTUP);

    srand(static_cast<unsigned int>(OTSYS_TIME()));
#ifdef _WIN32
    SetConsoleTitle(STATUS_SERVER_NAME);
#endif
    std::cout << "The " << STATUS_SERVER_NAME << " Version: (" << STATUS_SERVER_VERSION << "." << MINOR_VERSION << " . " << REVISION_VERSION << ") - Codename: ( " << SOFTWARE_CODENAME << " )" << std::endl;
    std::cout << "Compiled with: " << BOOST_COMPILER << std::endl;
    std::cout << "Compiled on " << __DATE__ << ' ' << __TIME__ << " for platform ";

#if defined(__amd64__) || defined(_M_X64)
    std::cout << "x64" << std::endl;
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_)
    std::cout << "x86" << std::endl;
#elif defined(__arm__)
    std::cout << "ARM" << std::endl;
#else
    std::cout << "unknown" << std::endl;
#endif
    std::cout << std::endl;

    std::cout << "A server developed by " << STATUS_SERVER_DEVELOPERS << "." << std::endl;
    std::cout << "Visit our forum for updates, support, and resources: " << GIT_REPO <<"." << std::endl;
    std::cout << std::endl;

    // read global config
    std::cout << ">> Loading config" << std::endl;
    if (!g_config.load()) {
        startupErrorMessage("Unable to load config.lua!");
        return;
    }

#ifdef _WIN32
    const std::string& defaultPriority = g_config.getString(ConfigManager::DEFAULT_PRIORITY);
    if (strcasecmp(defaultPriority.c_str(), "high") == 0) {
        SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
    } else if (strcasecmp(defaultPriority.c_str(), "above-normal") == 0) {
        SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
    }
#endif

    //set RSA key
    const char* p("14299623962416399520070177382898895550795403345466153217470516082934737582776038882967213386204600674145392845853859217990626450972452084065728686565928113");
    const char* q("7630979195970404721891201847792002125535401292779123937207447574596692788513647179235335529307251350570728407373705564708871762033017096809910315212884101");
    g_RSA.setKey(p, q);

    std::cout << ">> Establishing database connection..." << std::flush;

    Database* db = Database::getInstance();
    if (!db->connect()) {
        startupErrorMessage("Failed to connect to database.");
        return;
    }

    std::cout << " MySQL " << Database::getClientVersion() << std::endl;

    // run database manager
    std::cout << ">> Running database manager" << std::endl;

    if (!DatabaseManager::isDatabaseSetup()) {
        startupErrorMessage("The database you have specified in config.lua is empty, please import the schema.sql to your database.");
        return;
    }
    g_databaseTasks.start();

    DatabaseManager::updateDatabase();

    if (g_config.getBoolean(ConfigManager::OPTIMIZE_DATABASE) && !DatabaseManager::optimizeTables()) {
        std::cout << "> No tables were optimized." << std::endl;
    }

    //load vocations
    std::cout << ">> Loading vocations" << std::endl;
    if (!g_vocations.loadFromXml()) {
        startupErrorMessage("Unable to load vocations!");
        return;
    }

    // load item data
    std::cout << ">> Loading items" << std::endl;
    if (Item::items.loadFromOtb("data/items/items.otb") != ERROR_NONE) {
        startupErrorMessage("Unable to load items (OTB)!");
        return;
    }

    if (!Item::items.loadFromXml()) {
        startupErrorMessage("Unable to load items (XML)!");
        return;
    }

    std::cout << ">> Loading script systems" << std::endl;
    if (!ScriptingManager::getInstance()->loadScriptSystems()) {
        startupErrorMessage("Failed to load script systems");
        return;
    }

    std::cout << ">> Loading monsters" << std::endl;
    if (!g_monsters.loadFromXml()) {
        startupErrorMessage("Unable to load monsters!");
        return;
    }

    std::cout << ">> Loading outfits" << std::endl;
    Outfits* outfits = Outfits::getInstance();
    if (!outfits->loadFromXml()) {
        startupErrorMessage("Unable to load outfits!");
        return;
    }

    std::cout << ">> Checking world type... " << std::flush;
    std::string worldType = asLowerCaseString(g_config.getString(ConfigManager::WORLD_TYPE));
    if (worldType == "pvp") {
        g_game.setWorldType(WORLD_TYPE_PVP);
    } else if (worldType == "no-pvp") {
        g_game.setWorldType(WORLD_TYPE_NO_PVP);
    } else if (worldType == "pvp-enforced") {
        g_game.setWorldType(WORLD_TYPE_PVP_ENFORCED);
    } else {
        std::cout << std::endl;

        std::ostringstream ss;
        ss << "> ERROR: Unknown world type: " << g_config.getString(ConfigManager::WORLD_TYPE) << ", valid world types are: pvp, no-pvp and pvp-enforced.";
        startupErrorMessage(ss.str());
        return;
    }
    std::cout << asUpperCaseString(worldType) << std::endl;

    std::cout << ">> Loading map" << std::endl;
    if (!g_game.loadMainMap(g_config.getString(ConfigManager::MAP_NAME))) {
        startupErrorMessage("Failed to load map");
        return;
    }

    std::cout << ">> Initializing gamestate" << std::endl;
    g_game.setGameState(GAME_STATE_INIT);

    // Game client protocols
    services->add<ProtocolGame>(g_config.getNumber(ConfigManager::GAME_PORT));
    services->add<ProtocolLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT));

    // OT protocols
    services->add<ProtocolStatus>(g_config.getNumber(ConfigManager::STATUS_PORT));

    // Legacy login protocol
    services->add<ProtocolOld>(g_config.getNumber(ConfigManager::LOGIN_PORT));

    RentPeriod_t rentPeriod;
    std::string strRentPeriod = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));

    if (strRentPeriod == "yearly") {
        rentPeriod = RENTPERIOD_YEARLY;
    } else if (strRentPeriod == "weekly") {
        rentPeriod = RENTPERIOD_WEEKLY;
    } else if (strRentPeriod == "monthly") {
        rentPeriod = RENTPERIOD_MONTHLY;
    } else if (strRentPeriod == "daily") {
        rentPeriod = RENTPERIOD_DAILY;
    } else {
        rentPeriod = RENTPERIOD_NEVER;
    }

    g_game.map.houses.payHouses(rentPeriod);

    IOMarket::checkExpiredOffers();
    IOMarket::getInstance()->updateStatistics();

    std::cout << ">> Loaded all modules, server starting up..." << std::endl;

#ifndef _WIN32
    if (getuid() == 0 || geteuid() == 0) {
        std::cout << "> Warning: " << STATUS_SERVER_NAME << " has been executed as root user, please consider running it as a normal user." << std::endl;
    }
#endif

    g_game.start(services);
    g_game.setGameState(GAME_STATE_NORMAL);
    g_loaderSignal.notify_all();
}
void mainLoader(int, char*[], ServiceManager* services)
{

	srand(static_cast<unsigned int>(OTSYS_TIME()));
#ifdef _WIN32
	SetConsoleTitle(STATUS_SERVER_NAME);
#endif
	std::cout << STATUS_SERVER_NAME << " - Version " << STATUS_SERVER_VERSION << std::endl;
	std::cout << "Compiled with " << BOOST_COMPILER << std::endl;
	std::cout << "Compiled on " << __DATE__ << ' ' << __TIME__ << " for platform ";

#if defined(__amd64__) || defined(_M_X64)
	std::cout << "x64" << std::endl;
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_)
	std::cout << "x86" << std::endl;
#elif defined(__arm__)
	std::cout << "ARM" << std::endl;
#else
	std::cout << "unknown" << std::endl;
#endif
	std::cout << std::endl;

	std::cout << "A server developed by " << STATUS_SERVER_DEVELOPERS << std::endl;
	std::cout << "Visit our forum for updates, support, and resources: http://otland.net/." << std::endl;
	std::cout << std::endl;

	// read global config
	std::cout << ">> Loading config" << std::endl;
	if (!g_config.load()) {
		startupErrorMessage("Unable to load config.lua!");
		return;
	}

	std::cout << ">> Loading gameserver config..." << std::endl;

	if (!g_gameserver.load()) {
		startupErrorMessage("Unable to load gameservers!");
		return;
	}

#ifdef _WIN32
	const std::string& defaultPriority = g_config.getString(ConfigManager::DEFAULT_PRIORITY);
	if (strcasecmp(defaultPriority.c_str(), "high") == 0) {
		SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
	} else if (strcasecmp(defaultPriority.c_str(), "above-normal") == 0) {
		SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
	}
#endif

	//set RSA key
	const char* p("14299623962416399520070177382898895550795403345466153217470516082934737582776038882967213386204600674145392845853859217990626450972452084065728686565928113");
	const char* q("7630979195970404721891201847792002125535401292779123937207447574596692788513647179235335529307251350570728407373705564708871762033017096809910315212884101");
	g_RSA.setKey(p, q);

	std::cout << ">> Establishing database connection..." << std::flush;

	Database* db = Database::getInstance();
	if (!db->connect()) {
		startupErrorMessage("Failed to connect to database.");
		return;
	}

	std::cout << " MySQL " << Database::getClientVersion() << std::endl;

	// run database manager
	std::cout << ">> Running database manager" << std::endl;

	if (!DatabaseManager::isDatabaseSetup()) {
		startupErrorMessage("The database you have specified in config.lua is empty, please import the schema.sql to your database.");
		return;
	}
	g_databaseTasks.start();

	if (g_config.getBoolean(ConfigManager::OPTIMIZE_DATABASE) && !DatabaseManager::optimizeTables()) {
		std::cout << "> No tables were optimized." << std::endl;
	}

	services->add<ProtocolLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT));
	services->add<ProtocolOld>(g_config.getNumber(ConfigManager::LOGIN_PORT));

	std::cout << ">> Loaded all modules, server starting up..." << std::endl;

#ifndef _WIN32
	if (getuid() == 0 || geteuid() == 0) {
		std::cout << "> Warning: " << STATUS_SERVER_NAME << " has been executed as root user, please consider running it as a normal user." << std::endl;
	}
#endif

	g_loaderSignal.notify_all();
}
bool GlobalEvent::configureEvent(const pugi::xml_node& node)
{
	pugi::xml_attribute nameAttribute = node.attribute("name");
	if (!nameAttribute) {
		std::cout << "[Error - GlobalEvent::configureEvent] Missing name for a globalevent" << std::endl;
		return false;
	}

	m_name = nameAttribute.as_string();
	m_eventType = GLOBALEVENT_NONE;

	pugi::xml_attribute attr;
	if ((attr = node.attribute("time"))) {
		std::vector<int32_t> params = vectorAtoi(explodeString(attr.as_string(), ":"));
		if (params.front() < 0 || params.front() > 23) {
			std::cout << "[Error - GlobalEvent::configureEvent] Invalid hour \"" << attr.as_string() << "\" for globalevent with name: " << m_name << std::endl;
			return false;
		}

		m_interval |= params.front() << 16;
		int32_t hour = params.front();
		int32_t min = 0;
		int32_t sec = 0;

		if (params.size() > 1) {
			if (params[1] < 0 || params[1] > 59) {
				std::cout << "[Error - GlobalEvent::configureEvent] Invalid minute \"" << attr.as_string() << "\" for globalevent with name: " << m_name << std::endl;
				return false;
			}

			min = params[1];

			if (params.size() > 2) {
				if (params[2] < 0 || params[2] > 59) {
					std::cout << "[Error - GlobalEvent::configureEvent] Invalid second \"" << attr.as_string() << "\" for globalevent with name: " << m_name << std::endl;
					return false;
				}

				sec = params[2];
			}
		}

		time_t current_time = time(nullptr);
		tm* timeinfo = localtime(&current_time);
		timeinfo->tm_hour = hour;
		timeinfo->tm_min = min;
		timeinfo->tm_sec = sec;
		time_t difference = (time_t)difftime(mktime(timeinfo), current_time);

		if (difference < 0) {
			difference += 86400;
		}

		m_nextExecution = current_time + difference;
		m_eventType = GLOBALEVENT_TIMER;
	} else if ((attr = node.attribute("type"))) {
		std::string tmpStrValue = asLowerCaseString(attr.as_string());
		if (tmpStrValue == "startup" || tmpStrValue == "start" || tmpStrValue == "load") {
			m_eventType = GLOBALEVENT_STARTUP;
		} else if (tmpStrValue == "shutdown" || tmpStrValue == "quit" || tmpStrValue == "exit") {
			m_eventType = GLOBALEVENT_SHUTDOWN;
		} else if (tmpStrValue == "record" || tmpStrValue == "playersrecord") {
			m_eventType = GLOBALEVENT_RECORD;
		} else {
			std::cout << "[Error - GlobalEvent::configureEvent] No valid type \"" << attr.as_string() << "\" for globalevent with name " << m_name << std::endl;
			return false;
		}
	} else if ((attr = node.attribute("interval"))) {
		m_interval = std::max<int32_t>(SCHEDULER_MINTICKS, pugi::cast<int32_t>(attr.value()));
		m_nextExecution = OTSYS_TIME() + m_interval;
	} else {
		std::cout << "[Error - GlobalEvent::configureEvent] No interval for globalevent with name " << m_name << std::endl;
		return false;
	}
	return true;
}
Exemple #23
0
long long Protocol::getSleepTicks()
{
	long long delay = 0;
	int stepDuration = 0;

	Tile *tile =game->getTile(player->pos.x, player->pos.y, player->pos.z);
	if(tile && tile->ground) {
		int groundid = tile->ground->getID();

		uint8_t stepspeed = Item::items[groundid].speed;
		if(stepspeed != 0) {
			stepDuration = player->getStepDuration(stepspeed);

			if(player->lastmove != 0) {
				delay = (((long long)(player->lastmove)) + ((long long)(stepDuration))) - ((long long)(OTSYS_TIME()));
			}
		}
	}

	return delay;
}
bool IOMap::loadMap(Map* map, const std::string& identifier)
{
	int64_t start = OTSYS_TIME();

	FileLoader f;
	if (!f.openFile(identifier.c_str(), "OTBM")) {
		std::ostringstream ss;
		ss << "Could not open the file " << identifier << '.';
		setLastErrorString(ss.str());
		return false;
	}

	uint32_t type;
	PropStream propStream;

	NODE root = f.getChildNode(nullptr, type);
	if (!f.getProps(root, propStream)) {
		setLastErrorString("Could not read root property.");
		return false;
	}

	const OTBM_root_header* root_header;
	if (!propStream.readStruct(root_header)) {
		setLastErrorString("Could not read header.");
		return false;
	}

	uint32_t headerVersion = root_header->version;
	if (headerVersion <= 0) {
		//In otbm version 1 the count variable after splashes/fluidcontainers and stackables
		//are saved as attributes instead, this solves alot of problems with items
		//that is changed (stackable/charges/fluidcontainer/splash) during an update.
		setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly.");
		return false;
	}

	if (headerVersion > 2) {
		setLastErrorString("Unknown OTBM version detected.");
		return false;
	}

	if (root_header->majorVersionItems < 3) {
		setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly.");
		return false;
	}

	if (root_header->majorVersionItems > Items::dwMajorVersion) {
		setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required.");
		return false;
	}

	if (root_header->minorVersionItems < CLIENT_VERSION_810) {
		setLastErrorString("This map needs to be updated.");
		return false;
	}

	if (root_header->minorVersionItems > Items::dwMinorVersion) {
		std::cout << "[Warning - IOMap::loadMap] This map needs an updated items.otb." << std::endl;
	}

	std::cout << "> Map size: " << root_header->width << "x" << root_header->height << '.' << std::endl;
	map->width = root_header->width;
	map->height = root_header->height;

	NODE nodeMap = f.getChildNode(root, type);
	if (type != OTBM_MAP_DATA) {
		setLastErrorString("Could not read data node.");
		return false;
	}

	if (!f.getProps(nodeMap, propStream)) {
		setLastErrorString("Could not read map data attributes.");
		return false;
	}

	std::string mapDescription;
	std::string tmp;

	uint8_t attribute;
	while (propStream.read<uint8_t>(attribute)) {
		switch (attribute) {
			case OTBM_ATTR_DESCRIPTION:
				if (!propStream.readString(mapDescription)) {
					setLastErrorString("Invalid description tag.");
					return false;
				}
				break;

			case OTBM_ATTR_EXT_SPAWN_FILE:
				if (!propStream.readString(tmp)) {
					setLastErrorString("Invalid spawn tag.");
					return false;
				}

				map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1);
				map->spawnfile += tmp;
				break;

			case OTBM_ATTR_EXT_HOUSE_FILE:
				if (!propStream.readString(tmp)) {
					setLastErrorString("Invalid house tag.");
					return false;
				}

				map->housefile = identifier.substr(0, identifier.rfind('/') + 1);
				map->housefile += tmp;
				break;

			default:
				setLastErrorString("Unknown header node.");
				return false;
		}
	}

	NODE nodeMapData = f.getChildNode(nodeMap, type);
	while (nodeMapData != NO_NODE) {
		if (f.getError() != ERROR_NONE) {
			setLastErrorString("Invalid map node.");
			return false;
		}

		if (type == OTBM_TILE_AREA) {
			if (!f.getProps(nodeMapData, propStream)) {
				setLastErrorString("Invalid map node.");
				return false;
			}

			const OTBM_Destination_coords* area_coord;
			if (!propStream.readStruct(area_coord)) {
				setLastErrorString("Invalid map node.");
				return false;
			}

			int32_t base_x = area_coord->x;
			int32_t base_y = area_coord->y;
			int32_t base_z = area_coord->z;

			NODE nodeTile = f.getChildNode(nodeMapData, type);
			while (nodeTile != NO_NODE) {
				if (f.getError() != ERROR_NONE) {
					setLastErrorString("Could not read node data.");
					return false;
				}

				if (type != OTBM_TILE && type != OTBM_HOUSETILE) {
					setLastErrorString("Unknown tile node.");
					return false;
				}

				if (!f.getProps(nodeTile, propStream)) {
					setLastErrorString("Could not read node data.");
					return false;
				}

				const OTBM_Tile_coords* tile_coord;
				if (!propStream.readStruct(tile_coord)) {
					setLastErrorString("Could not read tile position.");
					return false;
				}

				uint16_t px = base_x + tile_coord->x;
				uint16_t py = base_y + tile_coord->y;
				uint16_t pz = base_z;

				bool isHouseTile = false;
				House* house = nullptr;
				Tile* tile = nullptr;
				Item* ground_item = nullptr;
				uint32_t tileflags = TILESTATE_NONE;

				if (type == OTBM_HOUSETILE) {
					uint32_t houseId;
					if (!propStream.read<uint32_t>(houseId)) {
						std::ostringstream ss;
						ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not read house id.";
						setLastErrorString(ss.str());
						return false;
					}

					house = map->houses.addHouse(houseId);
					if (!house) {
						std::ostringstream ss;
						ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not create house id: " << houseId;
						setLastErrorString(ss.str());
						return false;
					}

					tile = new HouseTile(px, py, pz, house);
					house->addTile(reinterpret_cast<HouseTile*>(tile));
					isHouseTile = true;
				}

				//read tile attributes
				while (propStream.read<uint8_t>(attribute)) {
					switch (attribute) {
						case OTBM_ATTR_TILE_FLAGS: {
							uint32_t flags;
							if (!propStream.read<uint32_t>(flags)) {
								std::ostringstream ss;
								ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to read tile flags.";
								setLastErrorString(ss.str());
								return false;
							}

							if ((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) {
								tileflags |= TILESTATE_PROTECTIONZONE;
							} else if ((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) {
								tileflags |= TILESTATE_NOPVPZONE;
							} else if ((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) {
								tileflags |= TILESTATE_PVPZONE;
							}

							if ((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) {
								tileflags |= TILESTATE_NOLOGOUT;
							}
							break;
						}

						case OTBM_ATTR_ITEM: {
							Item* item = Item::CreateItem(propStream);
							if (!item) {
								std::ostringstream ss;
								ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item.";
								setLastErrorString(ss.str());
								return false;
							}

							if (isHouseTile && item->isMoveable()) {
								std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl;
								delete item;
							} else {
								if (item->getItemCount() <= 0) {
									item->setItemCount(1);
								}

								if (tile) {
									tile->internalAddThing(item);
									item->startDecaying();
									item->setLoadedFromMap(true);
								} else if (item->isGroundTile()) {
									delete ground_item;
									ground_item = item;
								} else {
									tile = createTile(ground_item, item, px, py, pz);
									tile->internalAddThing(item);
									item->startDecaying();
									item->setLoadedFromMap(true);
								}
							}
							break;
						}

						default:
							std::ostringstream ss;
							ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown tile attribute.";
							setLastErrorString(ss.str());
							return false;
					}
				}

				NODE nodeItem = f.getChildNode(nodeTile, type);
				while (nodeItem) {
					if (type != OTBM_ITEM) {
						std::ostringstream ss;
						ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown node type.";
						setLastErrorString(ss.str());
						return false;
					}

					PropStream stream;
					if (!f.getProps(nodeItem, stream)) {
						setLastErrorString("Invalid item node.");
						return false;
					}

					Item* item = Item::CreateItem(stream);
					if (!item) {
						std::ostringstream ss;
						ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item.";
						setLastErrorString(ss.str());
						return false;
					}

					if (!item->unserializeItemNode(f, nodeItem, stream)) {
						std::ostringstream ss;
						ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to load item " << item->getID() << '.';
						setLastErrorString(ss.str());
						delete item;
						return false;
					}

					if (isHouseTile && item->isMoveable()) {
						std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << px << ", y: " << py << ", z: " << pz << "]." << std::endl;
						delete item;
					} else {
						if (item->getItemCount() <= 0) {
							item->setItemCount(1);
						}

						if (tile) {
							tile->internalAddThing(item);
							item->startDecaying();
							item->setLoadedFromMap(true);
						} else if (item->isGroundTile()) {
							delete ground_item;
							ground_item = item;
						} else {
							tile = createTile(ground_item, item, px, py, pz);
							tile->internalAddThing(item);
							item->startDecaying();
							item->setLoadedFromMap(true);
						}
					}

					nodeItem = f.getNextNode(nodeItem, type);
				}

				if (!tile) {
					tile = createTile(ground_item, nullptr, px, py, pz);
				}

				tile->setFlag(static_cast<tileflags_t>(tileflags));

				map->setTile(px, py, pz, tile);

				nodeTile = f.getNextNode(nodeTile, type);
			}
		} else if (type == OTBM_TOWNS) {
			NODE nodeTown = f.getChildNode(nodeMapData, type);
			while (nodeTown != NO_NODE) {
				if (type != OTBM_TOWN) {
					setLastErrorString("Unknown town node.");
					return false;
				}

				if (!f.getProps(nodeTown, propStream)) {
					setLastErrorString("Could not read town data.");
					return false;
				}

				uint32_t townId;
				if (!propStream.read<uint32_t>(townId)) {
					setLastErrorString("Could not read town id.");
					return false;
				}

				Town* town = map->towns.getTown(townId);
				if (!town) {
					town = new Town(townId);
					map->towns.addTown(townId, town);
				}

				std::string townName;
				if (!propStream.readString(townName)) {
					setLastErrorString("Could not read town name.");
					return false;
				}

				town->setName(townName);

				const OTBM_Destination_coords* town_coords;
				if (!propStream.readStruct(town_coords)) {
					setLastErrorString("Could not read town coordinates.");
					return false;
				}

				town->setTemplePos(Position(town_coords->x, town_coords->y, town_coords->z));

				nodeTown = f.getNextNode(nodeTown, type);
			}
		} else if (type == OTBM_WAYPOINTS && headerVersion > 1) {
			NODE nodeWaypoint = f.getChildNode(nodeMapData, type);
			while (nodeWaypoint != NO_NODE) {
				if (type != OTBM_WAYPOINT) {
					setLastErrorString("Unknown waypoint node.");
					return false;
				}

				if (!f.getProps(nodeWaypoint, propStream)) {
					setLastErrorString("Could not read waypoint data.");
					return false;
				}

				std::string name;
				if (!propStream.readString(name)) {
					setLastErrorString("Could not read waypoint name.");
					return false;
				}

				const OTBM_Destination_coords* waypoint_coords;
				if (!propStream.readStruct(waypoint_coords)) {
					setLastErrorString("Could not read waypoint coordinates.");
					return false;
				}

				map->waypoints[name] = Position(waypoint_coords->x, waypoint_coords->y, waypoint_coords->z);

				nodeWaypoint = f.getNextNode(nodeWaypoint, type);
			}
		} else {
			setLastErrorString("Unknown map node.");
			return false;
		}

		nodeMapData = f.getNextNode(nodeMapData, type);
	}

	std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
	return true;
}
Exemple #25
0
void otserv(
#if !defined(WINDOWS) || defined(_CONSOLE)
StringVec,
#endif
ServiceManager* services)
{
	std::srand((uint32_t)OTSYS_TIME());
#if defined(WINDOWS)
#if defined(_CONSOLE)
	SetConsoleTitle(SOFTWARE_NAME);
#else
	GUI::getInstance()->m_connections = false;
#endif
#endif

	g_game.setGameState(GAMESTATE_STARTUP);
#if !defined(WINDOWS) && !defined(__ROOT_PERMISSION__)
	if(!getuid() || !geteuid())
	{
		std::clog << "> WARNING: " "The " << SOFTWARE_NAME << " has been executed as super user! It is "
			<< "recommended to run as a normal user." << std::endl << "Continue? (y/N)" << std::endl;
		char buffer = OTSYS_getch();
		if(buffer != 121 && buffer != 89)
			startupErrorMessage("Aborted.");
	}
#endif

	std::clog << "The " << SOFTWARE_NAME << " Version: (" << SOFTWARE_VERSION << "." << MINOR_VERSION << PATCH_VERSION << " - " << REVISION_VERSION << ") - Codename: (" << SOFTWARE_CODENAME << ")" << std::endl
		<< "Compilied with " << BOOST_COMPILER << " for arch "
		#if defined(__amd64__) || defined(_M_X64)
		"64 Bits"
		#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_)
		"32 Bits"
		#else
		"unk"
		#endif
		" at " << __DATE__ << " " << __TIME__ << std::endl

		<< std::endl
		<< "A server developed by: "SOFTWARE_DEVELOPERS"." << std::endl
		<< "Visit our forums for updates, support, and resources:" << std::endl
		<< ""FORUMS"" << std::endl;
	std::stringstream ss;
#ifdef __DEBUG__
	ss << " GLOBAL";
#endif
#ifdef __DEBUG_MOVESYS__
	ss << " MOVESYS";
#endif
#ifdef __DEBUG_CHAT__
	ss << " CHAT";
#endif
#ifdef __DEBUG_HOUSES__
	ss << " HOUSES";
#endif
#ifdef __DEBUG_LUASCRIPTS__
	ss << " LUA-SCRIPTS";
#endif
#ifdef __DEBUG_MAILBOX__
	ss << " MAILBOX";
#endif
#ifdef __DEBUG_NET__
	ss << " NET";
#endif
#ifdef __DEBUG_NET_DETAIL__
	ss << " NET-DETAIL";
#endif
#ifdef __DEBUG_RAID__
	ss << " RAIDS";
#endif
#ifdef __DEBUG_SCHEDULER__
	ss << " SCHEDULER";
#endif
#ifdef __DEBUG_SPAWN__
	ss << " SPAWNS";
#endif
#ifdef __SQL_QUERY_DEBUG__
	ss << " SQL-QUERIES";
#endif

	std::string debug = ss.str();
	if(!debug.empty())
	{
		std::clog << ">> Debugging:";
		#if defined(WINDOWS) && !defined(_CONSOLE)
		SendMessage(GUI::getInstance()->m_statusBar, WM_SETTEXT, 0, (LPARAM)">> Debugging:");
		#endif
		std::clog << debug << "." << std::endl;
	}
	std::clog << std::endl;
	std::clog << ">> Loading config (" << g_config.getString(ConfigManager::CONFIG_FILE) << ")" << std::endl;
	#if defined(WINDOWS) && !defined(_CONSOLE)
	SendMessage(GUI::getInstance()->m_statusBar, WM_SETTEXT, 0, (LPARAM)">> Loading config");
	#endif
	if(!g_config.load())
		startupErrorMessage("Unable to load " + g_config.getString(ConfigManager::CONFIG_FILE) + "!");

#ifndef WINDOWS
	if(g_config.getBool(ConfigManager::DAEMONIZE))
	{
		std::clog << "> Daemonization... ";
		if(fork())
		{
			std::clog << "succeed, bye!" << std::endl;
			exit(0);
		}
		else
			std::clog << "failed, continuing." << std::endl;
	}

#endif
	// silently append trailing slash
	std::string path = g_config.getString(ConfigManager::DATA_DIRECTORY);
	g_config.setString(ConfigManager::DATA_DIRECTORY, path.erase(path.find_last_not_of("/") + 1) + "/");

	path = g_config.getString(ConfigManager::LOGS_DIRECTORY);
	g_config.setString(ConfigManager::LOGS_DIRECTORY, path.erase(path.find_last_not_of("/") + 1) + "/");

	std::clog << ">> Opening logs" << std::endl;
	#if defined(WINDOWS) && !defined(_CONSOLE)
	SendMessage(GUI::getInstance()->m_statusBar, WM_SETTEXT, 0, (LPARAM)">> Opening logs");
	#endif
	Logger::getInstance()->open();

	IntegerVec cores = vectorAtoi(explodeString(g_config.getString(ConfigManager::CORES_USED), ","));
	if(cores[0] != -1)
	{
#ifdef WINDOWS
		int32_t mask = 0;
		for(IntegerVec::iterator it = cores.begin(); it != cores.end(); ++it)
			mask += 1 << (*it);

		SetProcessAffinityMask(GetCurrentProcess(), mask);
	}

	std::stringstream mutexName;
	mutexName << "otxserver_" << g_config.getNumber(ConfigManager::WORLD_ID);

	CreateMutex(NULL, FALSE, mutexName.str().c_str());
	if(GetLastError() == ERROR_ALREADY_EXISTS)
		startupErrorMessage("Another instance of The OTX Server is already running with the same worldId.\nIf you want to run multiple servers, please change the worldId in configuration file.");

	std::string defaultPriority = asLowerCaseString(g_config.getString(ConfigManager::DEFAULT_PRIORITY));
	if(defaultPriority == "realtime" || defaultPriority == "real")
		SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
	else if(defaultPriority == "high" || defaultPriority == "regular")
		SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
	else if(defaultPriority == "higher" || defaultPriority == "above" || defaultPriority == "normal")
		SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);

#else
#ifndef __APPLE__
		cpu_set_t mask;
		CPU_ZERO(&mask);
		for(IntegerVec::iterator it = cores.begin(); it != cores.end(); ++it)
			CPU_SET((*it), &mask);

		sched_setaffinity(getpid(), (int32_t)sizeof(mask), &mask);
	}
Exemple #26
0
void OutputMessagePool::startExecutionFrame()
{
	m_frameTime = OTSYS_TIME();
	m_shutdown = false;
}
Exemple #27
0
int main(int argc, char* argv[])
{
#if defined WIN32 || defined __WINDOWS__
	WSADATA wsd;
	if(WSAStartup(MAKEWORD(2,2), &wsd) != 0){
		return 1;
	}
	
	LARGE_INTEGER counter;
	QueryPerformanceCounter(&counter);
	srand(counter.LowPart);
	
#else

	srand(time(NULL));
#endif
	
	
	disconnect_function = getCommand("disconnect", true);
	ping_function = getCommand("ping", true);

	char command[1024];
	long lineCounter = 0;
	long exit_code = 0;
	
	std::stringstream is;
	if(argc > 1){
		for(int i = 1; i < argc; ++i){
			is << argv[i] << std::endl;
		}
	}
	else{
		is << std::cin.rdbuf();
	}

	while(!is.eof()){
		lineCounter++;
		is.getline(command, 1024);
		if(strcmp(command, "") != 0){
			//comments line
			if(command[0] == '#'){
				continue;
			}
			//lower case until first space
			for(int i = 0; i < strlen(command) && command[i] != ' '; ++i){
				command[i] = tolower(command[i]);
				if(command[i] == '\r'){
					command[i] = 0;
					break;
				}
			}
			
			if(strlen(command) == 0)
				continue;
			
			CommandLine* commandLine;
			if(commandLine = parseLine(command)){
				commands_queue.push_back(commandLine);
			}
			else{
				std::cout << "Syntax error in line " << lineCounter << " " << command << std::endl;
				//clear commands
				COMMANDS_QUEUE::iterator it;
				for(it = commands_queue.begin(); it != commands_queue.end(); ++it){
					delete[] (*it)->params;
					delete *it;
				}
				commands_queue.clear();
				return 1;
			}
		}
	}

	//execute commands now
	NetworkMessage msg;
	COMMANDS_QUEUE::iterator it = commands_queue.begin();
	long last_ping = 0;
	while(it != commands_queue.end()){
		OTSYS_SLEEP(250);
		last_ping = last_ping + 250;
		if(next_command_delay > 250){
			next_command_delay = next_command_delay - 250;
		}
		else{
			next_command_delay = 0;
			long long time = OTSYS_TIME();

			//execute the command
			int retCode = (*it)->function((*it)->params);

			if(retCode == 1){
				//everything was ok
				++it;
			}
			else if(retCode == 2){
				//timeout
			}
			else{
				//error in the command
				exit_code = 1;
				break;
			}

			last_ping += (OTSYS_TIME() - time);
		}

		if(!g_shutdown && last_ping > 10000){
			//send ping here
			ping_function(NULL);
			last_ping = 0;
		}
	}
	//if connected end the connection
	if(g_connected){
		disconnect_function(NULL);
	}

	//free it
	for(it = commands_queue.begin(); it != commands_queue.end(); ++it){
		delete[] (*it)->params;
		delete *it;
	}
	commands_queue.clear();
#if defined WIN32 || defined __WINDOWS__
	WSACleanup();
#endif
	return exit_code;
}
Exemple #28
0
void Condition::setTicks(int32_t newTicks)
{
	ticks = newTicks;
	endTime = ticks + OTSYS_TIME();
}
bool Condition::updateCondition(const Condition* addCondition)
{
	return conditionType == addCondition->getType() && (ticks != -1 || addCondition->getTicks() < 1)
		&& (addCondition->getTicks() < 0 || endTime <= (OTSYS_TIME() + addCondition->getTicks()));
}
void OutputMessagePool::startExecutionFrame()
{
	//std::lock_guard<std::recursive_mutex> lockClass(m_outputPoolLock);
	m_frameTime = OTSYS_TIME();
	m_isOpen = true;
}