Server upload

RD Core / Commit #2

Commit Server upload

Alex Alex committed 18/10/2026 23:38 main Patch
1,106 files +223,404 -0
A src/condition.h +432-0 View file
@@ -0,0 +1,432 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_CONDITION_H_F92FF8BDDD5B4EA59E2B1BB5C9C0A086
21+#define FS_CONDITION_H_F92FF8BDDD5B4EA59E2B1BB5C9C0A086
22+
23+#include "fileloader.h"
24+#include "enums.h"
25+
26+class Creature;
27+class Player;
28+class PropStream;
29+
30+enum ConditionAttr_t {
31+ CONDITIONATTR_TYPE = 1,
32+ CONDITIONATTR_ID,
33+ CONDITIONATTR_TICKS,
34+ CONDITIONATTR_HEALTHTICKS,
35+ CONDITIONATTR_HEALTHGAIN,
36+ CONDITIONATTR_MANATICKS,
37+ CONDITIONATTR_MANAGAIN,
38+ CONDITIONATTR_DELAYED,
39+ CONDITIONATTR_OWNER,
40+ CONDITIONATTR_INTERVALDATA,
41+ CONDITIONATTR_SPEEDDELTA,
42+ CONDITIONATTR_FORMULA_MINA,
43+ CONDITIONATTR_FORMULA_MINB,
44+ CONDITIONATTR_FORMULA_MAXA,
45+ CONDITIONATTR_FORMULA_MAXB,
46+ CONDITIONATTR_LIGHTCOLOR,
47+ CONDITIONATTR_LIGHTLEVEL,
48+ CONDITIONATTR_LIGHTTICKS,
49+ CONDITIONATTR_LIGHTINTERVAL,
50+ CONDITIONATTR_SOULTICKS,
51+ CONDITIONATTR_SOULGAIN,
52+ CONDITIONATTR_SKILLS,
53+ CONDITIONATTR_STATS,
54+ CONDITIONATTR_OUTFIT,
55+ CONDITIONATTR_PERIODDAMAGE,
56+ CONDITIONATTR_ISBUFF,
57+ CONDITIONATTR_SUBID,
58+ CONDITIONATTR_ISAGGRESSIVE,
59+ CONDITIONATTR_DISABLEDEFENSE,
60+
61+ //reserved for serialization
62+ CONDITIONATTR_END = 254,
63+};
64+
65+struct IntervalInfo {
66+ int32_t timeLeft;
67+ int32_t value;
68+ int32_t interval;
69+};
70+
71+class Condition
72+{
73+ public:
74+ Condition() = default;
75+ Condition(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
76+ endTime(ticks == -1 ? std::numeric_limits<int64_t>::max() : 0),
77+ subId(subId), ticks(ticks), conditionType(type), isBuff(buff), aggressive(aggressive), id(id) {}
78+ virtual ~Condition() = default;
79+
80+ virtual bool startCondition(Creature* creature);
81+ virtual bool executeCondition(Creature* creature, int32_t interval);
82+ virtual void endCondition(Creature* creature) = 0;
83+ virtual void addCondition(Creature* creature, const Condition* condition) = 0;
84+ virtual uint32_t getIcons() const;
85+ ConditionId_t getId() const {
86+ return id;
87+ }
88+ uint32_t getSubId() const {
89+ return subId;
90+ }
91+
92+ virtual Condition* clone() const = 0;
93+
94+ ConditionType_t getType() const {
95+ return conditionType;
96+ }
97+ int64_t getEndTime() const {
98+ return endTime;
99+ }
100+ int32_t getTicks() const {
101+ return ticks;
102+ }
103+ void setTicks(int32_t newTicks);
104+ bool isAggressive() const {
105+ return aggressive;
106+ }
107+
108+ static Condition* createCondition(ConditionId_t id, ConditionType_t type, int32_t ticks, int32_t param = 0, bool buff = false, uint32_t subId = 0, bool aggressive = false);
109+ static Condition* createCondition(PropStream& propStream);
110+
111+ virtual bool setParam(ConditionParam_t param, int32_t value);
112+
113+ //serialization
114+ bool unserialize(PropStream& propStream);
115+ virtual void serialize(PropWriteStream& propWriteStream);
116+ virtual bool unserializeProp(ConditionAttr_t attr, PropStream& propStream);
117+
118+ bool isPersistent() const;
119+
120+ protected:
121+ virtual bool updateCondition(const Condition* addCondition);
122+
123+ int64_t endTime;
124+ uint32_t subId;
125+ int32_t ticks;
126+ ConditionType_t conditionType;
127+ bool isBuff;
128+ bool aggressive;
129+
130+ private:
131+ ConditionId_t id;
132+};
133+
134+class ConditionGeneric : public Condition
135+{
136+ public:
137+ ConditionGeneric(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false):
138+ Condition(id, type, ticks, buff, subId, aggressive) {}
139+
140+ bool startCondition(Creature* creature) override;
141+ bool executeCondition(Creature* creature, int32_t interval) override;
142+ void endCondition(Creature* creature) override;
143+ void addCondition(Creature* creature, const Condition* condition) override;
144+ uint32_t getIcons() const override;
145+
146+ ConditionGeneric* clone() const override {
147+ return new ConditionGeneric(*this);
148+ }
149+};
150+
151+class ConditionAttributes final : public ConditionGeneric
152+{
153+ public:
154+ ConditionAttributes(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
155+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
156+
157+ bool startCondition(Creature* creature) override;
158+ bool executeCondition(Creature* creature, int32_t interval) override;
159+ void endCondition(Creature* creature) override;
160+ void addCondition(Creature* creature, const Condition* condition) override;
161+
162+ bool setParam(ConditionParam_t param, int32_t value) override;
163+
164+ ConditionAttributes* clone() const override {
165+ return new ConditionAttributes(*this);
166+ }
167+
168+ //serialization
169+ void serialize(PropWriteStream& propWriteStream) override;
170+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
171+
172+ private:
173+ int32_t skills[SKILL_LAST + 1] = {};
174+ int32_t skillsPercent[SKILL_LAST + 1] = {};
175+ int32_t specialSkills[SPECIALSKILL_LAST + 1] = {};
176+ int32_t stats[STAT_LAST + 1] = {};
177+ int32_t statsPercent[STAT_LAST + 1] = {};
178+ int32_t currentSkill = 0;
179+ int32_t currentStat = 0;
180+
181+ bool disableDefense = false;
182+
183+ void updatePercentStats(Player* player);
184+ void updateStats(Player* player);
185+ void updatePercentSkills(Player* player);
186+ void updateSkills(Player* player);
187+};
188+
189+class ConditionRegeneration final : public ConditionGeneric
190+{
191+ public:
192+ ConditionRegeneration(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false):
193+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
194+
195+ void addCondition(Creature* creature, const Condition* condition) override;
196+ bool executeCondition(Creature* creature, int32_t interval) override;
197+
198+ bool setParam(ConditionParam_t param, int32_t value) override;
199+
200+ ConditionRegeneration* clone() const override {
201+ return new ConditionRegeneration(*this);
202+ }
203+
204+ //serialization
205+ void serialize(PropWriteStream& propWriteStream) override;
206+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
207+
208+ private:
209+ uint32_t internalHealthTicks = 0;
210+ uint32_t internalManaTicks = 0;
211+
212+ uint32_t healthTicks = 1000;
213+ uint32_t manaTicks = 1000;
214+ uint32_t healthGain = 0;
215+ uint32_t manaGain = 0;
216+};
217+
218+class ConditionSoul final : public ConditionGeneric
219+{
220+ public:
221+ ConditionSoul(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
222+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
223+
224+ void addCondition(Creature* creature, const Condition* condition) override;
225+ bool executeCondition(Creature* creature, int32_t interval) override;
226+
227+ bool setParam(ConditionParam_t param, int32_t value) override;
228+
229+ ConditionSoul* clone() const override {
230+ return new ConditionSoul(*this);
231+ }
232+
233+ //serialization
234+ void serialize(PropWriteStream& propWriteStream) override;
235+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
236+
237+ private:
238+ uint32_t internalSoulTicks = 0;
239+ uint32_t soulTicks = 0;
240+ uint32_t soulGain = 0;
241+};
242+
243+class ConditionInvisible final : public ConditionGeneric
244+{
245+ public:
246+ ConditionInvisible(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
247+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
248+
249+ bool startCondition(Creature* creature) override;
250+ void endCondition(Creature* creature) override;
251+
252+ ConditionInvisible* clone() const override {
253+ return new ConditionInvisible(*this);
254+ }
255+};
256+
257+class ConditionDamage final : public Condition
258+{
259+ public:
260+ ConditionDamage() = default;
261+ ConditionDamage(ConditionId_t id, ConditionType_t type, bool buff = false, uint32_t subId = 0, bool aggressive = true) :
262+ Condition(id, type, 0, buff, subId, aggressive) {}
263+
264+ static void generateDamageList(int32_t amount, int32_t start, std::list<int32_t>& list);
265+
266+ bool startCondition(Creature* creature) override;
267+ bool executeCondition(Creature* creature, int32_t interval) override;
268+ void endCondition(Creature* creature) override;
269+ void addCondition(Creature* creature, const Condition* condition) override;
270+ uint32_t getIcons() const override;
271+
272+ ConditionDamage* clone() const override {
273+ return new ConditionDamage(*this);
274+ }
275+
276+ bool setParam(ConditionParam_t param, int32_t value) override;
277+
278+ bool addDamage(int32_t rounds, int32_t time, int32_t value);
279+ bool doForceUpdate() const {
280+ return forceUpdate;
281+ }
282+ int32_t getTotalDamage() const;
283+
284+ void setInitDamage(int32_t initDamage) {
285+ this->initDamage = initDamage;
286+ }
287+
288+ //serialization
289+ void serialize(PropWriteStream& propWriteStream) override;
290+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
291+
292+ private:
293+ int32_t maxDamage = 0;
294+ int32_t minDamage = 0;
295+ int32_t startDamage = 0;
296+ int32_t periodDamage = 0;
297+ int32_t periodDamageTick = 0;
298+ int32_t tickInterval = 2000;
299+ int32_t initDamage = 0;
300+
301+ bool forceUpdate = false;
302+ bool delayed = false;
303+ bool field = false;
304+ uint32_t owner = 0;
305+
306+ bool init();
307+
308+ std::list<IntervalInfo> damageList;
309+
310+ bool getNextDamage(int32_t& damage);
311+ bool doDamage(Creature* creature, int32_t healthChange);
312+
313+ bool updateCondition(const Condition* addCondition) override;
314+};
315+
316+class ConditionSpeed final : public Condition
317+{
318+ public:
319+ ConditionSpeed(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff, uint32_t subId, int32_t changeSpeed, bool aggressive = false) :
320+ Condition(id, type, ticks, buff, subId, aggressive), speedDelta(changeSpeed) {}
321+
322+ bool startCondition(Creature* creature) override;
323+ bool executeCondition(Creature* creature, int32_t interval) override;
324+ void endCondition(Creature* creature) override;
325+ void addCondition(Creature* creature, const Condition* condition) override;
326+ uint32_t getIcons() const override;
327+
328+ ConditionSpeed* clone() const override {
329+ return new ConditionSpeed(*this);
330+ }
331+
332+ bool setParam(ConditionParam_t param, int32_t value) override;
333+
334+ void setFormulaVars(float mina, float minb, float maxa, float maxb);
335+
336+ //serialization
337+ void serialize(PropWriteStream& propWriteStream) override;
338+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
339+
340+ private:
341+ void getFormulaValues(int32_t var, int32_t& min, int32_t& max) const;
342+
343+ int32_t speedDelta;
344+
345+ //formula variables
346+ float mina = 0.0f;
347+ float minb = 0.0f;
348+ float maxa = 0.0f;
349+ float maxb = 0.0f;
350+};
351+
352+class ConditionOutfit final : public Condition
353+{
354+ public:
355+ ConditionOutfit(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
356+ Condition(id, type, ticks, buff, subId, aggressive) {}
357+
358+ bool startCondition(Creature* creature) override;
359+ bool executeCondition(Creature* creature, int32_t interval) override;
360+ void endCondition(Creature* creature) override;
361+ void addCondition(Creature* creature, const Condition* condition) override;
362+
363+ ConditionOutfit* clone() const override {
364+ return new ConditionOutfit(*this);
365+ }
366+
367+ void setOutfit(const Outfit_t& outfit);
368+
369+ //serialization
370+ void serialize(PropWriteStream& propWriteStream) override;
371+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
372+
373+ private:
374+ Outfit_t outfit;
375+};
376+
377+class ConditionLight final : public Condition
378+{
379+ public:
380+ ConditionLight(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff, uint32_t subId, uint8_t lightlevel, uint8_t lightcolor, bool aggressive = false) :
381+ Condition(id, type, ticks, buff, subId, aggressive), lightInfo(lightlevel, lightcolor) {}
382+
383+ bool startCondition(Creature* creature) override;
384+ bool executeCondition(Creature* creature, int32_t interval) override;
385+ void endCondition(Creature* creature) override;
386+ void addCondition(Creature* creature, const Condition* condition) override;
387+
388+ ConditionLight* clone() const override {
389+ return new ConditionLight(*this);
390+ }
391+
392+ bool setParam(ConditionParam_t param, int32_t value) override;
393+
394+ //serialization
395+ void serialize(PropWriteStream& propWriteStream) override;
396+ bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
397+
398+ private:
399+ LightInfo lightInfo;
400+ uint32_t internalLightTicks = 0;
401+ uint32_t lightChangeInterval = 0;
402+};
403+
404+class ConditionSpellCooldown final : public ConditionGeneric
405+{
406+ public:
407+ ConditionSpellCooldown(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
408+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
409+
410+ bool startCondition(Creature* creature) override;
411+ void addCondition(Creature* creature, const Condition* condition) override;
412+
413+ ConditionSpellCooldown* clone() const override {
414+ return new ConditionSpellCooldown(*this);
415+ }
416+};
417+
418+class ConditionSpellGroupCooldown final : public ConditionGeneric
419+{
420+ public:
421+ ConditionSpellGroupCooldown(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0, bool aggressive = false) :
422+ ConditionGeneric(id, type, ticks, buff, subId, aggressive) {}
423+
424+ bool startCondition(Creature* creature) override;
425+ void addCondition(Creature* creature, const Condition* condition) override;
426+
427+ ConditionSpellGroupCooldown* clone() const override {
428+ return new ConditionSpellGroupCooldown(*this);
429+ }
430+};
431+
432+#endif
A src/configmanager.cpp +242-0 View file
@@ -0,0 +1,242 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#include "otpch.h"
21+
22+#if defined(_MSC_VER)
23+extern "C"
24+{
25+#include <luajit/lua.h>
26+#include <luajit/lualib.h>
27+#include <luajit/lauxlib.h>
28+}
29+#else
30+#include <lua.hpp>
31+#endif
32+
33+#include "configmanager.h"
34+#include "game.h"
35+
36+#if LUA_VERSION_NUM >= 502
37+#undef lua_strlen
38+#define lua_strlen lua_rawlen
39+#endif
40+
41+extern Game g_game;
42+
43+namespace {
44+
45+std::string getGlobalString(lua_State* L, const char* identifier, const char* defaultValue)
46+{
47+ lua_getglobal(L, identifier);
48+ if (!lua_isstring(L, -1)) {
49+ lua_pop(L, 1);
50+ return defaultValue;
51+ }
52+
53+ size_t len = lua_strlen(L, -1);
54+ std::string ret(lua_tostring(L, -1), len);
55+ lua_pop(L, 1);
56+ return ret;
57+}
58+
59+int32_t getGlobalNumber(lua_State* L, const char* identifier, const int32_t defaultValue = 0)
60+{
61+ lua_getglobal(L, identifier);
62+ if (!lua_isnumber(L, -1)) {
63+ lua_pop(L, 1);
64+ return defaultValue;
65+ }
66+
67+ int32_t val = lua_tonumber(L, -1);
68+ lua_pop(L, 1);
69+ return val;
70+}
71+
72+bool getGlobalBoolean(lua_State* L, const char* identifier, const bool defaultValue)
73+{
74+ lua_getglobal(L, identifier);
75+ if (!lua_isboolean(L, -1)) {
76+ if (!lua_isstring(L, -1)) {
77+ lua_pop(L, 1);
78+ return defaultValue;
79+ }
80+
81+ size_t len = lua_strlen(L, -1);
82+ std::string ret(lua_tostring(L, -1), len);
83+ lua_pop(L, 1);
84+ return booleanString(ret);
85+ }
86+
87+ int val = lua_toboolean(L, -1);
88+ lua_pop(L, 1);
89+ return val != 0;
90+}
91+
92+}
93+
94+bool ConfigManager::load()
95+{
96+ lua_State* L = luaL_newstate();
97+ if (!L) {
98+ throw std::runtime_error("Failed to allocate memory");
99+ }
100+
101+ luaL_openlibs(L);
102+
103+ if (luaL_dofile(L, "config.lua")) {
104+ std::cout << "[Error - ConfigManager::load] " << lua_tostring(L, -1) << std::endl;
105+ lua_close(L);
106+ return false;
107+ }
108+
109+ //parse config
110+ if (!loaded) { //info that must be loaded one time (unless we reset the modules involved)
111+ boolean[BIND_ONLY_GLOBAL_ADDRESS] = getGlobalBoolean(L, "bindOnlyGlobalAddress", false);
112+ boolean[OPTIMIZE_DATABASE] = getGlobalBoolean(L, "startupDatabaseOptimization", true);
113+
114+ string[IP] = getGlobalString(L, "ip", "127.0.0.1");
115+ string[MAP_NAME] = getGlobalString(L, "mapName", "forgotten");
116+ string[MAP_AUTHOR] = getGlobalString(L, "mapAuthor", "Unknown");
117+ string[HOUSE_RENT_PERIOD] = getGlobalString(L, "houseRentPeriod", "never");
118+ string[MYSQL_HOST] = getGlobalString(L, "mysqlHost", "127.0.0.1");
119+ string[MYSQL_USER] = getGlobalString(L, "mysqlUser", "forgottenserver");
120+ string[MYSQL_PASS] = getGlobalString(L, "mysqlPass", "");
121+ string[MYSQL_DB] = getGlobalString(L, "mysqlDatabase", "forgottenserver");
122+ string[MYSQL_SOCK] = getGlobalString(L, "mysqlSock", "");
123+
124+ integer[SQL_PORT] = getGlobalNumber(L, "mysqlPort", 3306);
125+ integer[GAME_PORT] = getGlobalNumber(L, "gameProtocolPort", 7172);
126+ integer[LOGIN_PORT] = getGlobalNumber(L, "loginProtocolPort", 7171);
127+ integer[STATUS_PORT] = getGlobalNumber(L, "statusProtocolPort", 7171);
128+
129+ integer[MARKET_OFFER_DURATION] = getGlobalNumber(L, "marketOfferDuration", 30 * 24 * 60 * 60);
130+ }
131+
132+ boolean[ALLOW_CHANGEOUTFIT] = getGlobalBoolean(L, "allowChangeOutfit", true);
133+ boolean[ONE_PLAYER_ON_ACCOUNT] = getGlobalBoolean(L, "onePlayerOnlinePerAccount", true);
134+ boolean[AIMBOT_HOTKEY_ENABLED] = getGlobalBoolean(L, "hotkeyAimbotEnabled", true);
135+ boolean[REMOVE_RUNE_CHARGES] = getGlobalBoolean(L, "removeChargesFromRunes", true);
136+ boolean[REMOVE_WEAPON_AMMO] = getGlobalBoolean(L, "removeWeaponAmmunition", true);
137+ boolean[REMOVE_WEAPON_CHARGES] = getGlobalBoolean(L, "removeWeaponCharges", true);
138+ boolean[REMOVE_POTION_CHARGES] = getGlobalBoolean(L, "removeChargesFromPotions", true);
139+ boolean[EXPERIENCE_FROM_PLAYERS] = getGlobalBoolean(L, "experienceByKillingPlayers", false);
140+ boolean[FREE_PREMIUM] = getGlobalBoolean(L, "freePremium", false);
141+ boolean[REPLACE_KICK_ON_LOGIN] = getGlobalBoolean(L, "replaceKickOnLogin", true);
142+ boolean[ALLOW_CLONES] = getGlobalBoolean(L, "allowClones", false);
143+ boolean[MARKET_PREMIUM] = getGlobalBoolean(L, "premiumToCreateMarketOffer", true);
144+ boolean[EMOTE_SPELLS] = getGlobalBoolean(L, "emoteSpells", false);
145+ boolean[STAMINA_SYSTEM] = getGlobalBoolean(L, "staminaSystem", true);
146+ boolean[WARN_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "warnUnsafeScripts", true);
147+ boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
148+ boolean[CLASSIC_EQUIPMENT_SLOTS] = getGlobalBoolean(L, "classicEquipmentSlots", false);
149+ boolean[CLASSIC_ATTACK_SPEED] = getGlobalBoolean(L, "classicAttackSpeed", false);
150+ boolean[SCRIPTS_CONSOLE_LOGS] = getGlobalBoolean(L, "showScriptsLogInConsole", true);
151+ boolean[SERVER_SAVE_NOTIFY_MESSAGE] = getGlobalBoolean(L, "serverSaveNotifyMessage", true);
152+ boolean[SERVER_SAVE_CLEAN_MAP] = getGlobalBoolean(L, "serverSaveCleanMap", false);
153+ boolean[SERVER_SAVE_CLOSE] = getGlobalBoolean(L, "serverSaveClose", false);
154+ boolean[SERVER_SAVE_SHUTDOWN] = getGlobalBoolean(L, "serverSaveShutdown", true);
155+ boolean[ONLINE_OFFLINE_CHARLIST] = getGlobalBoolean(L, "showOnlineStatusInCharlist", false);
156+ boolean[YELL_ALLOW_PREMIUM] = getGlobalBoolean(L, "yellAlwaysAllowPremium", false);
157+ boolean[FORCE_MONSTERTYPE_LOAD] = getGlobalBoolean(L, "forceMonsterTypesOnLoad", true);
158+ boolean[HOUSE_OWNED_BY_ACCOUNT] = getGlobalBoolean(L, "houseOwnedByAccount", false);
159+ boolean[CLEAN_PROTECTION_ZONES] = getGlobalBoolean(L, "cleanProtectionZones", false);
160+ boolean[HOUSE_DOOR_SHOW_PRICE] = getGlobalBoolean(L, "houseDoorShowPrice", true);
161+ boolean[PACKET_COMPRESSION] = getGlobalBoolean(L, "packetCompression", true);
162+
163+ string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
164+ string[SERVER_NAME] = getGlobalString(L, "serverName", "");
165+ string[OWNER_NAME] = getGlobalString(L, "ownerName", "");
166+ string[OWNER_EMAIL] = getGlobalString(L, "ownerEmail", "");
167+ string[URL] = getGlobalString(L, "url", "");
168+ string[LOCATION] = getGlobalString(L, "location", "");
169+ string[MOTD] = getGlobalString(L, "motd", "");
170+ string[WORLD_TYPE] = getGlobalString(L, "worldType", "pvp");
171+
172+ integer[MAX_PLAYERS] = getGlobalNumber(L, "maxPlayers");
173+ integer[PZ_LOCKED] = getGlobalNumber(L, "pzLocked", 60000);
174+ integer[DEFAULT_DESPAWNRANGE] = getGlobalNumber(L, "deSpawnRange", 2);
175+ integer[DEFAULT_DESPAWNRADIUS] = getGlobalNumber(L, "deSpawnRadius", 50);
176+ integer[RATE_EXPERIENCE] = getGlobalNumber(L, "rateExp", 5);
177+ integer[RATE_SKILL] = getGlobalNumber(L, "rateSkill", 3);
178+ integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 2);
179+ integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 3);
180+ integer[RATE_SPAWN] = getGlobalNumber(L, "rateSpawn", 1);
181+ integer[HOUSE_PRICE] = getGlobalNumber(L, "housePriceEachSQM", 1000);
182+ integer[KILLS_TO_RED] = getGlobalNumber(L, "killsToRedSkull", 3);
183+ integer[KILLS_TO_BLACK] = getGlobalNumber(L, "killsToBlackSkull", 6);
184+ integer[ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenActions", 200);
185+ integer[EX_ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenExActions", 1000);
186+ integer[MAX_MESSAGEBUFFER] = getGlobalNumber(L, "maxMessageBuffer", 4);
187+ integer[KICK_AFTER_MINUTES] = getGlobalNumber(L, "kickIdlePlayerAfterMinutes", 15);
188+ integer[PROTECTION_LEVEL] = getGlobalNumber(L, "protectionLevel", 1);
189+ integer[DEATH_LOSE_PERCENT] = getGlobalNumber(L, "deathLosePercent", -1);
190+ integer[STATUSQUERY_TIMEOUT] = getGlobalNumber(L, "statusTimeout", 5000);
191+ integer[FRAG_TIME] = getGlobalNumber(L, "timeToDecreaseFrags", 24 * 60 * 60);
192+ integer[WHITE_SKULL_TIME] = getGlobalNumber(L, "whiteSkullTime", 15 * 60);
193+ integer[STAIRHOP_DELAY] = getGlobalNumber(L, "stairJumpExhaustion", 2000);
194+ integer[EXP_FROM_PLAYERS_LEVEL_RANGE] = getGlobalNumber(L, "expFromPlayersLevelRange", 75);
195+ integer[CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES] = getGlobalNumber(L, "checkExpiredMarketOffersEachMinutes", 60);
196+ integer[MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER] = getGlobalNumber(L, "maxMarketOffersAtATimePerPlayer", 100);
197+ integer[MAX_PACKETS_PER_SECOND] = getGlobalNumber(L, "maxPacketsPerSecond", 25);
198+ integer[SERVER_SAVE_NOTIFY_DURATION] = getGlobalNumber(L, "serverSaveNotifyDuration", 5);
199+ integer[YELL_MINIMUM_LEVEL] = getGlobalNumber(L, "yellMinimumLevel", 2);
200+
201+ loaded = true;
202+ lua_close(L);
203+ return true;
204+}
205+
206+bool ConfigManager::reload()
207+{
208+ bool result = load();
209+ if (transformToSHA1(getString(ConfigManager::MOTD)) != g_game.getMotdHash()) {
210+ g_game.incrementMotdNum();
211+ }
212+ return result;
213+}
214+
215+static std::string dummyStr;
216+
217+const std::string& ConfigManager::getString(string_config_t what) const
218+{
219+ if (what >= LAST_STRING_CONFIG) {
220+ std::cout << "[Warning - ConfigManager::getString] Accessing invalid index: " << what << std::endl;
221+ return dummyStr;
222+ }
223+ return string[what];
224+}
225+
226+int32_t ConfigManager::getNumber(integer_config_t what) const
227+{
228+ if (what >= LAST_INTEGER_CONFIG) {
229+ std::cout << "[Warning - ConfigManager::getNumber] Accessing invalid index: " << what << std::endl;
230+ return 0;
231+ }
232+ return integer[what];
233+}
234+
235+bool ConfigManager::getBoolean(boolean_config_t what) const
236+{
237+ if (what >= LAST_BOOLEAN_CONFIG) {
238+ std::cout << "[Warning - ConfigManager::getBoolean] Accessing invalid index: " << what << std::endl;
239+ return false;
240+ }
241+ return boolean[what];
242+}
A src/configmanager.h +138-0 View file
@@ -0,0 +1,138 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
21+#define FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
22+
23+class ConfigManager
24+{
25+ public:
26+ enum boolean_config_t {
27+ ALLOW_CHANGEOUTFIT,
28+ ONE_PLAYER_ON_ACCOUNT,
29+ AIMBOT_HOTKEY_ENABLED,
30+ REMOVE_RUNE_CHARGES,
31+ REMOVE_WEAPON_AMMO,
32+ REMOVE_WEAPON_CHARGES,
33+ REMOVE_POTION_CHARGES,
34+ EXPERIENCE_FROM_PLAYERS,
35+ FREE_PREMIUM,
36+ REPLACE_KICK_ON_LOGIN,
37+ ALLOW_CLONES,
38+ BIND_ONLY_GLOBAL_ADDRESS,
39+ OPTIMIZE_DATABASE,
40+ MARKET_PREMIUM,
41+ EMOTE_SPELLS,
42+ STAMINA_SYSTEM,
43+ WARN_UNSAFE_SCRIPTS,
44+ CONVERT_UNSAFE_SCRIPTS,
45+ CLASSIC_EQUIPMENT_SLOTS,
46+ CLASSIC_ATTACK_SPEED,
47+ SCRIPTS_CONSOLE_LOGS,
48+ SERVER_SAVE_NOTIFY_MESSAGE,
49+ SERVER_SAVE_CLEAN_MAP,
50+ SERVER_SAVE_CLOSE,
51+ SERVER_SAVE_SHUTDOWN,
52+ ONLINE_OFFLINE_CHARLIST,
53+ YELL_ALLOW_PREMIUM,
54+ FORCE_MONSTERTYPE_LOAD,
55+ HOUSE_OWNED_BY_ACCOUNT,
56+ CLEAN_PROTECTION_ZONES,
57+ HOUSE_DOOR_SHOW_PRICE,
58+ PACKET_COMPRESSION,
59+
60+ LAST_BOOLEAN_CONFIG /* this must be the last one */
61+ };
62+
63+ enum string_config_t {
64+ MAP_NAME,
65+ HOUSE_RENT_PERIOD,
66+ SERVER_NAME,
67+ OWNER_NAME,
68+ OWNER_EMAIL,
69+ URL,
70+ LOCATION,
71+ IP,
72+ MOTD,
73+ WORLD_TYPE,
74+ MYSQL_HOST,
75+ MYSQL_USER,
76+ MYSQL_PASS,
77+ MYSQL_DB,
78+ MYSQL_SOCK,
79+ DEFAULT_PRIORITY,
80+ MAP_AUTHOR,
81+
82+ LAST_STRING_CONFIG /* this must be the last one */
83+ };
84+
85+ enum integer_config_t {
86+ SQL_PORT,
87+ MAX_PLAYERS,
88+ PZ_LOCKED,
89+ DEFAULT_DESPAWNRANGE,
90+ DEFAULT_DESPAWNRADIUS,
91+ RATE_EXPERIENCE,
92+ RATE_SKILL,
93+ RATE_LOOT,
94+ RATE_MAGIC,
95+ RATE_SPAWN,
96+ HOUSE_PRICE,
97+ KILLS_TO_RED,
98+ KILLS_TO_BLACK,
99+ MAX_MESSAGEBUFFER,
100+ ACTIONS_DELAY_INTERVAL,
101+ EX_ACTIONS_DELAY_INTERVAL,
102+ KICK_AFTER_MINUTES,
103+ PROTECTION_LEVEL,
104+ DEATH_LOSE_PERCENT,
105+ STATUSQUERY_TIMEOUT,
106+ FRAG_TIME,
107+ WHITE_SKULL_TIME,
108+ GAME_PORT,
109+ LOGIN_PORT,
110+ STATUS_PORT,
111+ STAIRHOP_DELAY,
112+ MARKET_OFFER_DURATION,
113+ CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES,
114+ MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER,
115+ EXP_FROM_PLAYERS_LEVEL_RANGE,
116+ MAX_PACKETS_PER_SECOND,
117+ SERVER_SAVE_NOTIFY_DURATION,
118+ YELL_MINIMUM_LEVEL,
119+
120+ LAST_INTEGER_CONFIG /* this must be the last one */
121+ };
122+
123+ bool load();
124+ bool reload();
125+
126+ const std::string& getString(string_config_t what) const;
127+ int32_t getNumber(integer_config_t what) const;
128+ bool getBoolean(boolean_config_t what) const;
129+
130+ private:
131+ std::string string[LAST_STRING_CONFIG] = {};
132+ int32_t integer[LAST_INTEGER_CONFIG] = {};
133+ bool boolean[LAST_BOOLEAN_CONFIG] = {};
134+
135+ bool loaded = false;
136+};
137+
138+#endif
A src/connection.cpp +313-0 View file
@@ -0,0 +1,313 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#include "otpch.h"
21+
22+#include "configmanager.h"
23+#include "connection.h"
24+#include "outputmessage.h"
25+#include "protocol.h"
26+#include "scheduler.h"
27+#include "server.h"
28+
29+extern ConfigManager g_config;
30+
31+Connection_ptr ConnectionManager::createConnection(boost::asio::io_service& io_service, ConstServicePort_ptr servicePort)
32+{
33+ std::lock_guard<std::mutex> lockClass(connectionManagerLock);
34+
35+ auto connection = std::make_shared<Connection>(io_service, servicePort);
36+ connections.insert(connection);
37+ return connection;
38+}
39+
40+void ConnectionManager::releaseConnection(const Connection_ptr& connection)
41+{
42+ std::lock_guard<std::mutex> lockClass(connectionManagerLock);
43+
44+ connections.erase(connection);
45+}
46+
47+void ConnectionManager::closeAll()
48+{
49+ std::lock_guard<std::mutex> lockClass(connectionManagerLock);
50+
51+ for (const auto& connection : connections) {
52+ try {
53+ boost::system::error_code error;
54+ connection->socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, error);
55+ connection->socket.close(error);
56+ } catch (boost::system::system_error&) {
57+ }
58+ }
59+ connections.clear();
60+}
61+
62+// Connection
63+
64+void Connection::close(bool force)
65+{
66+ //any thread
67+ ConnectionManager::getInstance().releaseConnection(shared_from_this());
68+
69+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
70+ if (connectionState != CONNECTION_STATE_OPEN) {
71+ return;
72+ }
73+ connectionState = CONNECTION_STATE_CLOSED;
74+
75+ if (protocol) {
76+ g_dispatcher.addTask(
77+ createTask(std::bind(&Protocol::release, protocol)));
78+ }
79+
80+ if (messageQueue.empty() || force) {
81+ closeSocket();
82+ } else {
83+ //will be closed by the destructor or onWriteOperation
84+ }
85+}
86+
87+void Connection::closeSocket()
88+{
89+ if (socket.is_open()) {
90+ try {
91+ readTimer.cancel();
92+ writeTimer.cancel();
93+ boost::system::error_code error;
94+ socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, error);
95+ socket.close(error);
96+ } catch (boost::system::system_error& e) {
97+ std::cout << "[Network error - Connection::closeSocket] " << e.what() << std::endl;
98+ }
99+ }
100+}
101+
102+Connection::~Connection()
103+{
104+ closeSocket();
105+}
106+
107+void Connection::accept(Protocol_ptr protocol)
108+{
109+ this->protocol = protocol;
110+ g_dispatcher.addTask(createTask(std::bind(&Protocol::onConnect, protocol)));
111+
112+ accept();
113+}
114+
115+void Connection::accept()
116+{
117+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
118+ try {
119+ readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
120+ readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()), std::placeholders::_1));
121+
122+ // Read size of the first packet
123+ boost::asio::async_read(socket,
124+ boost::asio::buffer(msg.getBuffer(), NetworkMessage::HEADER_LENGTH),
125+ std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1));
126+ } catch (boost::system::system_error& e) {
127+ std::cout << "[Network error - Connection::accept] " << e.what() << std::endl;
128+ close(FORCE_CLOSE);
129+ }
130+}
131+
132+void Connection::parseHeader(const boost::system::error_code& error)
133+{
134+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
135+ readTimer.cancel();
136+
137+ if (error) {
138+ close(FORCE_CLOSE);
139+ return;
140+ } else if (connectionState != CONNECTION_STATE_OPEN) {
141+ return;
142+ }
143+
144+ uint32_t timePassed = std::max<uint32_t>(1, (time(nullptr) - timeConnected) + 1);
145+ if ((++packetsSent / timePassed) > static_cast<uint32_t>(g_config.getNumber(ConfigManager::MAX_PACKETS_PER_SECOND))) {
146+ std::cout << convertIPToString(getIP()) << " disconnected for exceeding packet per second limit." << std::endl;
147+ close();
148+ return;
149+ }
150+
151+ if (timePassed > 2) {
152+ timeConnected = time(nullptr);
153+ packetsSent = 0;
154+ }
155+
156+ uint16_t size = msg.getLengthHeader();
157+ if (size == 0 || size >= NETWORKMESSAGE_MAXSIZE - 16) {
158+ close(FORCE_CLOSE);
159+ return;
160+ }
161+
162+ try {
163+ readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
164+ readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()),
165+ std::placeholders::_1));
166+
167+ // Read packet content
168+ msg.setLength(size + NetworkMessage::HEADER_LENGTH);
169+ boost::asio::async_read(socket, boost::asio::buffer(msg.getBodyBuffer(), size),
170+ std::bind(&Connection::parsePacket, shared_from_this(), std::placeholders::_1));
171+ } catch (boost::system::system_error& e) {
172+ std::cout << "[Network error - Connection::parseHeader] " << e.what() << std::endl;
173+ close(FORCE_CLOSE);
174+ }
175+}
176+
177+void Connection::parsePacket(const boost::system::error_code& error)
178+{
179+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
180+ readTimer.cancel();
181+
182+ if (error) {
183+ close(FORCE_CLOSE);
184+ return;
185+ } else if (connectionState != CONNECTION_STATE_OPEN) {
186+ return;
187+ }
188+
189+ //Check packet checksum
190+ uint32_t checksum;
191+ int32_t len = msg.getLength() - msg.getBufferPosition() - NetworkMessage::CHECKSUM_LENGTH;
192+ if (len > 0) {
193+ checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + NetworkMessage::CHECKSUM_LENGTH, len);
194+ } else {
195+ checksum = 0;
196+ }
197+
198+ uint32_t recvChecksum = msg.get<uint32_t>();
199+ if (recvChecksum != checksum) {
200+ // it might not have been the checksum, step back
201+ msg.skipBytes(-NetworkMessage::CHECKSUM_LENGTH);
202+ }
203+
204+ if (!receivedFirst) {
205+ // First message received
206+ receivedFirst = true;
207+
208+ if (!protocol) {
209+ // Game protocol has already been created at this point
210+ protocol = service_port->make_protocol(recvChecksum == checksum, msg, shared_from_this());
211+ if (!protocol) {
212+ close(FORCE_CLOSE);
213+ return;
214+ }
215+ } else {
216+ msg.skipBytes(1); // Skip protocol ID
217+ }
218+
219+ protocol->onRecvFirstMessage(msg);
220+ } else {
221+ protocol->onRecvMessage(msg); // Send the packet to the current protocol
222+ }
223+
224+ try {
225+ readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
226+ readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()),
227+ std::placeholders::_1));
228+
229+ // Wait to the next packet
230+ boost::asio::async_read(socket,
231+ boost::asio::buffer(msg.getBuffer(), NetworkMessage::HEADER_LENGTH),
232+ std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1));
233+ } catch (boost::system::system_error& e) {
234+ std::cout << "[Network error - Connection::parsePacket] " << e.what() << std::endl;
235+ close(FORCE_CLOSE);
236+ }
237+}
238+
239+void Connection::send(const OutputMessage_ptr& msg)
240+{
241+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
242+ if (connectionState != CONNECTION_STATE_OPEN) {
243+ return;
244+ }
245+
246+ bool noPendingWrite = messageQueue.empty();
247+ messageQueue.emplace_back(msg);
248+ if (noPendingWrite) {
249+ internalSend(msg);
250+ }
251+}
252+
253+void Connection::internalSend(const OutputMessage_ptr& msg)
254+{
255+ protocol->onSendMessage(msg);
256+ try {
257+ writeTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_WRITE_TIMEOUT));
258+ writeTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()),
259+ std::placeholders::_1));
260+
261+ boost::asio::async_write(socket,
262+ boost::asio::buffer(msg->getOutputBuffer(), msg->getLength()),
263+ std::bind(&Connection::onWriteOperation, shared_from_this(), std::placeholders::_1));
264+ } catch (boost::system::system_error& e) {
265+ std::cout << "[Network error - Connection::internalSend] " << e.what() << std::endl;
266+ close(FORCE_CLOSE);
267+ }
268+}
269+
270+uint32_t Connection::getIP()
271+{
272+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
273+
274+ // IP-address is expressed in network byte order
275+ boost::system::error_code error;
276+ const boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(error);
277+ if (error) {
278+ return 0;
279+ }
280+
281+ return htonl(endpoint.address().to_v4().to_ulong());
282+}
283+
284+void Connection::onWriteOperation(const boost::system::error_code& error)
285+{
286+ std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
287+ writeTimer.cancel();
288+ messageQueue.pop_front();
289+
290+ if (error) {
291+ messageQueue.clear();
292+ close(FORCE_CLOSE);
293+ return;
294+ }
295+
296+ if (!messageQueue.empty()) {
297+ internalSend(messageQueue.front());
298+ } else if (connectionState == CONNECTION_STATE_CLOSED) {
299+ closeSocket();
300+ }
301+}
302+
303+void Connection::handleTimeout(ConnectionWeak_ptr connectionWeak, const boost::system::error_code& error)
304+{
305+ if (error == boost::asio::error::operation_aborted) {
306+ //The timer has been manually cancelled
307+ return;
308+ }
309+
310+ if (auto connection = connectionWeak.lock()) {
311+ connection->close(FORCE_CLOSE);
312+ }
313+}
A src/connection.h +133-0 View file
@@ -0,0 +1,133 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_CONNECTION_H_FC8E1B4392D24D27A2F129D8B93A6348
21+#define FS_CONNECTION_H_FC8E1B4392D24D27A2F129D8B93A6348
22+
23+#include <unordered_set>
24+
25+#include "networkmessage.h"
26+
27+static constexpr int32_t CONNECTION_WRITE_TIMEOUT = 30;
28+static constexpr int32_t CONNECTION_READ_TIMEOUT = 30;
29+
30+class Protocol;
31+using Protocol_ptr = std::shared_ptr<Protocol>;
32+class OutputMessage;
33+using OutputMessage_ptr = std::shared_ptr<OutputMessage>;
34+class Connection;
35+using Connection_ptr = std::shared_ptr<Connection>;
36+using ConnectionWeak_ptr = std::weak_ptr<Connection>;
37+class ServiceBase;
38+using Service_ptr = std::shared_ptr<ServiceBase>;
39+class ServicePort;
40+using ServicePort_ptr = std::shared_ptr<ServicePort>;
41+using ConstServicePort_ptr = std::shared_ptr<const ServicePort>;
42+
43+class ConnectionManager
44+{
45+ public:
46+ static ConnectionManager& getInstance() {
47+ static ConnectionManager instance;
48+ return instance;
49+ }
50+
51+ Connection_ptr createConnection(boost::asio::io_service& io_service, ConstServicePort_ptr servicePort);
52+ void releaseConnection(const Connection_ptr& connection);
53+ void closeAll();
54+
55+ private:
56+ ConnectionManager() = default;
57+
58+ std::unordered_set<Connection_ptr> connections;
59+ std::mutex connectionManagerLock;
60+};
61+
62+class Connection : public std::enable_shared_from_this<Connection>
63+{
64+ public:
65+ // non-copyable
66+ Connection(const Connection&) = delete;
67+ Connection& operator=(const Connection&) = delete;
68+
69+ enum ConnectionState_t {
70+ CONNECTION_STATE_OPEN,
71+ CONNECTION_STATE_CLOSED,
72+ };
73+
74+ enum { FORCE_CLOSE = true };
75+
76+ Connection(boost::asio::io_service& io_service,
77+ ConstServicePort_ptr service_port) :
78+ readTimer(io_service),
79+ writeTimer(io_service),
80+ service_port(std::move(service_port)),
81+ socket(io_service),
82+ timeConnected(time(nullptr)) {}
83+ ~Connection();
84+
85+ friend class ConnectionManager;
86+
87+ void close(bool force = false);
88+ // Used by protocols that require server to send first
89+ void accept(Protocol_ptr protocol);
90+ void accept();
91+
92+ void send(const OutputMessage_ptr& msg);
93+
94+ uint32_t getIP();
95+
96+ private:
97+ void parseHeader(const boost::system::error_code& error);
98+ void parsePacket(const boost::system::error_code& error);
99+
100+ void onWriteOperation(const boost::system::error_code& error);
101+
102+ static void handleTimeout(ConnectionWeak_ptr connectionWeak, const boost::system::error_code& error);
103+
104+ void closeSocket();
105+ void internalSend(const OutputMessage_ptr& msg);
106+
107+ boost::asio::ip::tcp::socket& getSocket() {
108+ return socket;
109+ }
110+ friend class ServicePort;
111+
112+ NetworkMessage msg;
113+
114+ boost::asio::deadline_timer readTimer;
115+ boost::asio::deadline_timer writeTimer;
116+
117+ std::recursive_mutex connectionLock;
118+
119+ std::list<OutputMessage_ptr> messageQueue;
120+
121+ ConstServicePort_ptr service_port;
122+ Protocol_ptr protocol;
123+
124+ boost::asio::ip::tcp::socket socket;
125+
126+ time_t timeConnected;
127+ uint32_t packetsSent = 0;
128+
129+ bool connectionState = CONNECTION_STATE_OPEN;
130+ bool receivedFirst = false;
131+};
132+
133+#endif
Top