mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-05-02 18:49:21 +02:00
introduce multiple client version support in config.lua and NPCs
This commit is contained in:
parent
ff7636b945
commit
0cd1af211e
@ -37,6 +37,7 @@ replaceKickOnLogin = true
|
|||||||
maxPacketsPerSecond = -1
|
maxPacketsPerSecond = -1
|
||||||
autoStackCumulatives = false
|
autoStackCumulatives = false
|
||||||
moneyRate = 1
|
moneyRate = 1
|
||||||
|
clientVersion = 780
|
||||||
|
|
||||||
-- Deaths
|
-- Deaths
|
||||||
-- NOTE: Leave deathLosePercent as -1 if you want to use the default
|
-- NOTE: Leave deathLosePercent as -1 if you want to use the default
|
||||||
|
@ -123,6 +123,7 @@ bool ConfigManager::load()
|
|||||||
integer[NEWBIE_TOWN] = getGlobalNumber(L, "newbieTownId", 1);
|
integer[NEWBIE_TOWN] = getGlobalNumber(L, "newbieTownId", 1);
|
||||||
integer[NEWBIE_LEVEL_THRESHOLD] = getGlobalNumber(L, "newbieLevelThreshold", 5);
|
integer[NEWBIE_LEVEL_THRESHOLD] = getGlobalNumber(L, "newbieLevelThreshold", 5);
|
||||||
integer[MONEY_RATE] = getGlobalNumber(L, "moneyRate", 1);
|
integer[MONEY_RATE] = getGlobalNumber(L, "moneyRate", 1);
|
||||||
|
integer[CLIENT_VERSION] = getGlobalNumber(L, "clientVersion");
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
|
@ -111,6 +111,7 @@ class ConfigManager
|
|||||||
NEWBIE_TOWN,
|
NEWBIE_TOWN,
|
||||||
NEWBIE_LEVEL_THRESHOLD,
|
NEWBIE_LEVEL_THRESHOLD,
|
||||||
MONEY_RATE,
|
MONEY_RATE,
|
||||||
|
CLIENT_VERSION,
|
||||||
|
|
||||||
LAST_INTEGER_CONFIG /* this must be the last one */
|
LAST_INTEGER_CONFIG /* this must be the last one */
|
||||||
};
|
};
|
||||||
|
@ -351,6 +351,13 @@ enum ReloadTypes_t : uint8_t {
|
|||||||
RELOAD_TYPE_WEAPONS,
|
RELOAD_TYPE_WEAPONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ClientVersion_t : uint16_t {
|
||||||
|
CLIENT_VERSION_780 = 780,
|
||||||
|
CLIENT_VERSION_781 = 781,
|
||||||
|
CLIENT_VERSION_790 = 790,
|
||||||
|
CLIENT_VERSION_792 = 792,
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr int32_t CHANNEL_GUILD = 0x00;
|
static constexpr int32_t CHANNEL_GUILD = 0x00;
|
||||||
static constexpr int32_t CHANNEL_PARTY = 0x01;
|
static constexpr int32_t CHANNEL_PARTY = 0x01;
|
||||||
static constexpr int32_t CHANNEL_RULE_REP = 0x02;
|
static constexpr int32_t CHANNEL_RULE_REP = 0x02;
|
||||||
|
@ -24,10 +24,6 @@ static constexpr auto STATUS_SERVER_NAME = "Sabrehaven";
|
|||||||
static constexpr auto STATUS_SERVER_VERSION = "1.0";
|
static constexpr auto STATUS_SERVER_VERSION = "1.0";
|
||||||
static constexpr auto STATUS_SERVER_DEVELOPERS = "OTLand community & Sabrehaven Developers Team";
|
static constexpr auto STATUS_SERVER_DEVELOPERS = "OTLand community & Sabrehaven Developers Team";
|
||||||
|
|
||||||
static constexpr auto CLIENT_VERSION_MIN = 780;
|
|
||||||
static constexpr auto CLIENT_VERSION_MAX = 781;
|
|
||||||
static constexpr auto CLIENT_VERSION_STR = "7.81";
|
|
||||||
|
|
||||||
static constexpr auto AUTHENTICATOR_DIGITS = 6U;
|
static constexpr auto AUTHENTICATOR_DIGITS = 6U;
|
||||||
static constexpr auto AUTHENTICATOR_PERIOD = 30U;
|
static constexpr auto AUTHENTICATOR_PERIOD = 30U;
|
||||||
|
|
||||||
|
@ -76,6 +76,11 @@ void Game::setWorldType(WorldType_t type)
|
|||||||
worldType = type;
|
worldType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::setClientVersion(ClientVersion_t version)
|
||||||
|
{
|
||||||
|
clientVersion = version;
|
||||||
|
}
|
||||||
|
|
||||||
void Game::setGameState(GameState_t newState)
|
void Game::setGameState(GameState_t newState)
|
||||||
{
|
{
|
||||||
if (gameState == GAME_STATE_SHUTDOWN) {
|
if (gameState == GAME_STATE_SHUTDOWN) {
|
||||||
|
@ -127,6 +127,11 @@ class Game
|
|||||||
return worldType;
|
return worldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setClientVersion(ClientVersion_t version);
|
||||||
|
ClientVersion_t getClientVersion() const {
|
||||||
|
return clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
Cylinder* internalGetCylinder(Player* player, const Position& pos) const;
|
Cylinder* internalGetCylinder(Player* player, const Position& pos) const;
|
||||||
Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
|
Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
|
||||||
uint32_t spriteId, stackPosType_t type) const;
|
uint32_t spriteId, stackPosType_t type) const;
|
||||||
@ -533,6 +538,7 @@ class Game
|
|||||||
|
|
||||||
GameState_t gameState = GAME_STATE_NORMAL;
|
GameState_t gameState = GAME_STATE_NORMAL;
|
||||||
WorldType_t worldType = WORLD_TYPE_PVP;
|
WorldType_t worldType = WORLD_TYPE_PVP;
|
||||||
|
ClientVersion_t clientVersion;
|
||||||
|
|
||||||
LightState_t lightState = LIGHT_STATE_DAY;
|
LightState_t lightState = LIGHT_STATE_DAY;
|
||||||
uint8_t lightLevel = LIGHT_LEVEL_DAY;
|
uint8_t lightLevel = LIGHT_LEVEL_DAY;
|
||||||
|
@ -1676,6 +1676,7 @@ void LuaScriptInterface::registerFunctions()
|
|||||||
registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD)
|
registerEnumIn("configKeys", ConfigManager::NEWBIE_LEVEL_THRESHOLD)
|
||||||
registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT)
|
registerEnumIn("configKeys", ConfigManager::BLOCK_HEIGHT)
|
||||||
registerEnumIn("configKeys", ConfigManager::DROP_ITEMS)
|
registerEnumIn("configKeys", ConfigManager::DROP_ITEMS)
|
||||||
|
registerEnumIn("configKeys", ConfigManager::CLIENT_VERSION)
|
||||||
|
|
||||||
// os
|
// os
|
||||||
registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime);
|
registerMethod("os", "mtime", LuaScriptInterface::luaSystemTime);
|
||||||
|
@ -51,8 +51,10 @@ void Npcs::loadNpcs()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (npc->getClientVersion() <= g_game.getClientVersion()) {
|
||||||
g_game.placeCreature(npc, npc->getMasterPos(), false, true);
|
g_game.placeCreature(npc, npc->getMasterPos(), false, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Npcs::reload()
|
void Npcs::reload()
|
||||||
@ -152,6 +154,8 @@ bool Npc::load()
|
|||||||
script.readCoordinate(masterPos.x, masterPos.y, masterPos.z);
|
script.readCoordinate(masterPos.x, masterPos.y, masterPos.z);
|
||||||
} else if (ident == "radius") {
|
} else if (ident == "radius") {
|
||||||
masterRadius = script.readNumber();
|
masterRadius = script.readNumber();
|
||||||
|
} else if (ident == "clientversion") {
|
||||||
|
clientVersion = script.readNumber();
|
||||||
} else if (ident == "behaviour") {
|
} else if (ident == "behaviour") {
|
||||||
if (behaviourDatabase) {
|
if (behaviourDatabase) {
|
||||||
script.error("behaviour database already defined");
|
script.error("behaviour database already defined");
|
||||||
|
@ -85,6 +85,9 @@ class Npc final : public Creature
|
|||||||
int32_t getMasterRadius() const {
|
int32_t getMasterRadius() const {
|
||||||
return masterRadius;
|
return masterRadius;
|
||||||
}
|
}
|
||||||
|
int32_t getClientVersion() const {
|
||||||
|
return clientVersion;
|
||||||
|
}
|
||||||
const Position& getMasterPos() const {
|
const Position& getMasterPos() const {
|
||||||
return masterPos;
|
return masterPos;
|
||||||
}
|
}
|
||||||
@ -141,6 +144,7 @@ class Npc final : public Creature
|
|||||||
uint32_t lastTalkCreature;
|
uint32_t lastTalkCreature;
|
||||||
uint32_t focusCreature;
|
uint32_t focusCreature;
|
||||||
uint32_t masterRadius;
|
uint32_t masterRadius;
|
||||||
|
uint16_t clientVersion = 0;
|
||||||
|
|
||||||
int64_t conversationStartTime;
|
int64_t conversationStartTime;
|
||||||
int64_t conversationEndTime;
|
int64_t conversationEndTime;
|
||||||
|
@ -245,6 +245,27 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
}
|
}
|
||||||
std::cout << asUpperCaseString(worldType) << std::endl;
|
std::cout << asUpperCaseString(worldType) << std::endl;
|
||||||
|
|
||||||
|
std::cout << ">> Checking client version... " << std::flush;
|
||||||
|
int32_t clientVersion = g_config.getNumber(ConfigManager::CLIENT_VERSION);
|
||||||
|
if (clientVersion == 780) {
|
||||||
|
g_game.setClientVersion(CLIENT_VERSION_780);
|
||||||
|
} else if (clientVersion == 781) {
|
||||||
|
g_game.setClientVersion(CLIENT_VERSION_781);
|
||||||
|
} else if (clientVersion == 790) {
|
||||||
|
g_game.setClientVersion(CLIENT_VERSION_790);
|
||||||
|
} else if (clientVersion == 792) {
|
||||||
|
g_game.setClientVersion(CLIENT_VERSION_792);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "> ERROR: Unknown client version: " << g_config.getNumber(ConfigManager::CLIENT_VERSION) << ", valid client versions are: 780, 781, 790, 792.";
|
||||||
|
startupErrorMessage(ss.str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cout << clientVersion << std::endl;
|
||||||
|
|
||||||
std::cout << ">> Loading map" << std::endl;
|
std::cout << ">> Loading map" << std::endl;
|
||||||
if (!g_game.loadMainMap(g_config.getString(ConfigManager::MAP_NAME))) {
|
if (!g_game.loadMainMap(g_config.getString(ConfigManager::MAP_NAME))) {
|
||||||
startupErrorMessage("Failed to load map");
|
startupErrorMessage("Failed to load map");
|
||||||
|
@ -1775,6 +1775,7 @@ void ProtocolGame::sendOutfitWindow()
|
|||||||
Outfit_t currentOutfit = player->getDefaultOutfit();
|
Outfit_t currentOutfit = player->getDefaultOutfit();
|
||||||
AddOutfit(msg, currentOutfit);
|
AddOutfit(msg, currentOutfit);
|
||||||
|
|
||||||
|
const ClientVersion_t clientVersion = g_game.getClientVersion();
|
||||||
std::vector<ProtocolOutfit> protocolOutfits;
|
std::vector<ProtocolOutfit> protocolOutfits;
|
||||||
if (player->isAccessPlayer()) {
|
if (player->isAccessPlayer()) {
|
||||||
static const std::string gamemasterOutfitName = "Gamemaster";
|
static const std::string gamemasterOutfitName = "Gamemaster";
|
||||||
@ -1790,14 +1791,19 @@ void ProtocolGame::sendOutfitWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons);
|
protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons);
|
||||||
if (protocolOutfits.size() == 15) { // Game client doesn't allow more than 15 outfits
|
if (CLIENT_VERSION_780 <= clientVersion && clientVersion <= CLIENT_VERSION_792) {
|
||||||
|
if (protocolOutfits.size() == 15) { // Game client doesn't allow more than 15 outfits in 780-792
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msg.addByte(protocolOutfits.size());
|
msg.addByte(protocolOutfits.size());
|
||||||
for (const ProtocolOutfit& outfit : protocolOutfits) {
|
for (const ProtocolOutfit& outfit : protocolOutfits) {
|
||||||
msg.add<uint16_t>(outfit.lookType);
|
msg.add<uint16_t>(outfit.lookType);
|
||||||
|
if (clientVersion > CLIENT_VERSION_781) {
|
||||||
|
msg.addString(outfit.name);
|
||||||
|
}
|
||||||
msg.addByte(outfit.addons);
|
msg.addByte(outfit.addons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ class ProtocolGame final : public Protocol
|
|||||||
|
|
||||||
uint32_t eventConnect = 0;
|
uint32_t eventConnect = 0;
|
||||||
uint32_t challengeTimestamp = 0;
|
uint32_t challengeTimestamp = 0;
|
||||||
uint16_t version = CLIENT_VERSION_MIN;
|
uint16_t version;
|
||||||
|
|
||||||
uint8_t challengeRandom = 0;
|
uint8_t challengeRandom = 0;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
|||||||
|
|
||||||
if (version <= 760) {
|
if (version <= 760) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "Only clients with protocol " << CLIENT_VERSION_STR << " allowed!";
|
ss << "Only clients with protocol " << getClientVersionString(g_game.getClientVersion()) << " allowed!";
|
||||||
disconnectClient(ss.str(), version);
|
disconnectClient(ss.str(), version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -136,9 +136,9 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
|||||||
enableXTEAEncryption();
|
enableXTEAEncryption();
|
||||||
setXTEAKey(key);
|
setXTEAKey(key);
|
||||||
|
|
||||||
if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
|
if (!isProtocolAllowed(version)) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "Only clients with protocol " << CLIENT_VERSION_STR << " allowed!";
|
ss << "Only clients with protocol " << getClientVersionString(g_game.getClientVersion()) << " allowed!";
|
||||||
disconnectClient(ss.str(), version);
|
disconnectClient(ss.str(), version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -185,3 +185,19 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
|||||||
auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
|
auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
|
||||||
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version)));
|
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ProtocolLogin::isProtocolAllowed(uint16_t version)
|
||||||
|
{
|
||||||
|
ClientVersion_t allowedClientVersion = g_game.getClientVersion();
|
||||||
|
|
||||||
|
if (allowedClientVersion == version)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (version == 781 && allowedClientVersion == CLIENT_VERSION_780) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -21,6 +21,7 @@
|
|||||||
#define FS_PROTOCOLLOGIN_H_1238F4B473074DF2ABC595C29E81C46D
|
#define FS_PROTOCOLLOGIN_H_1238F4B473074DF2ABC595C29E81C46D
|
||||||
|
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
class NetworkMessage;
|
class NetworkMessage;
|
||||||
class OutputMessage;
|
class OutputMessage;
|
||||||
@ -38,6 +39,7 @@ class ProtocolLogin : public Protocol
|
|||||||
explicit ProtocolLogin(Connection_ptr connection) : Protocol(connection) {}
|
explicit ProtocolLogin(Connection_ptr connection) : Protocol(connection) {}
|
||||||
|
|
||||||
void onRecvFirstMessage(NetworkMessage& msg) override;
|
void onRecvFirstMessage(NetworkMessage& msg) override;
|
||||||
|
bool isProtocolAllowed(uint16_t version);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void disconnectClient(const std::string& message, uint16_t version);
|
void disconnectClient(const std::string& message, uint16_t version);
|
||||||
|
@ -110,7 +110,7 @@ void ProtocolStatus::sendStatusString()
|
|||||||
serverinfo.append_attribute("url") = g_config.getString(ConfigManager::URL).c_str();
|
serverinfo.append_attribute("url") = g_config.getString(ConfigManager::URL).c_str();
|
||||||
serverinfo.append_attribute("server") = STATUS_SERVER_NAME;
|
serverinfo.append_attribute("server") = STATUS_SERVER_NAME;
|
||||||
serverinfo.append_attribute("version") = STATUS_SERVER_VERSION;
|
serverinfo.append_attribute("version") = STATUS_SERVER_VERSION;
|
||||||
serverinfo.append_attribute("client") = CLIENT_VERSION_STR;
|
serverinfo.append_attribute("client") = getClientVersionString(g_game.getClientVersion()).c_str();
|
||||||
|
|
||||||
pugi::xml_node owner = tsqp.append_child("owner");
|
pugi::xml_node owner = tsqp.append_child("owner");
|
||||||
owner.append_attribute("name") = g_config.getString(ConfigManager::OWNER_NAME).c_str();
|
owner.append_attribute("name") = g_config.getString(ConfigManager::OWNER_NAME).c_str();
|
||||||
@ -240,7 +240,7 @@ void ProtocolStatus::sendInfo(uint16_t requestedInfo, const std::string& charact
|
|||||||
output->addByte(0x23); // server software info
|
output->addByte(0x23); // server software info
|
||||||
output->addString(STATUS_SERVER_NAME);
|
output->addString(STATUS_SERVER_NAME);
|
||||||
output->addString(STATUS_SERVER_VERSION);
|
output->addString(STATUS_SERVER_VERSION);
|
||||||
output->addString(CLIENT_VERSION_STR);
|
output->addString(getClientVersionString(g_game.getClientVersion()));
|
||||||
}
|
}
|
||||||
send(output);
|
send(output);
|
||||||
disconnect();
|
disconnect();
|
||||||
|
@ -1230,3 +1230,33 @@ void getFilesInDirectory(const boost::filesystem::path& root, const std::string&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getClientVersionString(uint32_t version)
|
||||||
|
{
|
||||||
|
return getClientVersionString(static_cast<ClientVersion_t>(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getClientVersionString(ClientVersion_t version)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
switch (version)
|
||||||
|
{
|
||||||
|
case CLIENT_VERSION_780:
|
||||||
|
result = "7.80";
|
||||||
|
break;
|
||||||
|
case CLIENT_VERSION_781:
|
||||||
|
result = "7.81";
|
||||||
|
break;
|
||||||
|
case CLIENT_VERSION_790:
|
||||||
|
result = "7.90";
|
||||||
|
break;
|
||||||
|
case CLIENT_VERSION_792:
|
||||||
|
result = "7.92";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -100,6 +100,9 @@ const char* getReturnMessage(ReturnValue value);
|
|||||||
|
|
||||||
void getFilesInDirectory(const boost::filesystem::path& root, const std::string& ext, std::vector<boost::filesystem::path>& ret);
|
void getFilesInDirectory(const boost::filesystem::path& root, const std::string& ext, std::vector<boost::filesystem::path>& ret);
|
||||||
|
|
||||||
|
std::string getClientVersionString(uint32_t version);
|
||||||
|
std::string getClientVersionString(ClientVersion_t version);
|
||||||
|
|
||||||
inline int64_t OTSYS_TIME()
|
inline int64_t OTSYS_TIME()
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user