-
Posts
624 -
Joined
-
Last visited
-
Days Won
96 -
Feedback
100%
martysama0134 last won the day on September 23 2022
martysama0134 had the most liked content!
About martysama0134

Informations
-
Gender
Not Telling
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
martysama0134's Achievements
-
DnD started following martysama0134
-
Muska started following martysama0134
-
ArRigo started following martysama0134
-
ofithi started following martysama0134
-
sumaysayilkan started following martysama0134
-
Zack started following martysama0134
-
xSoLoYD started following martysama0134
-
tmihiw started following martysama0134
-
Reminder: On Windows, a batch script can't rename it directly Settings.txt -> settings.txt, but you must use a temporary name for it. The steps for "REN" are Settings.txt -> settings.txt_ -> settings.txt. Python os.rename works fine without a temporary name for it. #!/usr/bin/env python3 import os import sys def rename_to_lower(root_dir): # Walk the directory tree from the bottom up for current_path, directories, files in os.walk(root_dir, topdown=False): # Rename files in the current directory for filename in files: new_filename = filename.lower() if new_filename != filename: src = os.path.join(current_path, filename) dst = os.path.join(current_path, new_filename) if not os.path.exists(dst): os.rename(src, dst) print(f"Renamed file: '{src}' -> '{dst}'") else: print(f"Skipping file: target '{dst}' already exists.") # Rename directories in the current directory for dirname in directories: new_dirname = dirname.lower() if new_dirname != dirname: src = os.path.join(current_path, dirname) dst = os.path.join(current_path, new_dirname) if not os.path.exists(dst): os.rename(src, dst) print(f"Renamed directory: '{src}' -> '{dst}'") else: print(f"Skipping directory: target '{dst}' already exists.") def main(): if len(sys.argv) != 2: print("Usage: python3 lower_script.py <folder_path>") sys.exit(1) folder = sys.argv[1] if not os.path.isdir(folder): print(f"Error: '{folder}' is not a valid directory.") sys.exit(1) rename_to_lower(folder) if __name__ == '__main__': main() ty chatgpt
-
martysama0134 started following Patch for Bouquet Sync Damage Exploit
-
Patch for Bouquet Sync Damage Exploit
martysama0134 replied to Khabib Nurmagomedov's topic in Bug Fixes
The bouquet is using the subtype 10, and it's not in the ESubWeaponTypes enum. In the CHARACTER::Damage you can do this: bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead { if (pAttacker && pAttacker->IsPC() && pAttacker->GetWear(WEAR_WEAPON) && pAttacker->GetWear(WEAR_WEAPON)->GetSubType() >= WEAPON_NUM_TYPES) { SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK); return false; } Otherwise you create WEAPON_BOUQUET = 10, and edit it with bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead { if (pAttacker && pAttacker->IsPC() && pAttacker->GetWear(WEAR_WEAPON) && pAttacker->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_BOUQUET) { SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK); return false; } Or a mix of both: if (pAttacker && pAttacker->IsPC()) { const auto weapon = pAttacker->GetWear(WEAR_WEAPON); if (weapon && (weapon->GetSubType() >= WEAPON_NUM_TYPES || weapon->GetSubType() == WEAPON_BOUQUET)) { SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK); return false; } } -
claudio0028 started following martysama0134
-
77nick77 left Positive feedback for martysama0134
-
(MySQL) player.item table -> (Navicat) Design table -> add the offlineshop window in the relative window enum field if missing In your query the window type is 0 and not something like 8-9, which means the error is in the c++. I don't know which offlineshop system you have, but probably you miss something like this: case OFFLINESHOP_INVENTORY: if (wCell >= OFFLINESHOP_SLOT_MAX) { sys_err("CHARACTER::GetInventoryItem: invalid OS item cell %d", wCell); return NULL; } return m_pointsInstant.playerSlots->pOfflineItems[wCell]; Furthermore, using a REPLACE query is utter garbage and should be avoided at any cost in MySQL.
-
Some people requested me to refactor this library for c++20 without invalidating the old syntax. [Hidden Content] [Hidden Content] Here are the changes: changed std::string_view instead of std::string handling changed std::unordered_map instead of std::map supported new foreach pair syntax added missing const-ness rewritten CEventFunctionHandler::Process with std::erase_if replaced copy with impactless move for std::function removed Destroy() from destructor because unneeded for std containers removed SupportArg added looped events removed ProcessStatus disabled DelayEvent for looped events The usage is remained unchanged, except the support for looped timers. // Create the event and call it after 5 seconds. Using "this" as argument is safe only if it's a singleton, for CHARACTER or CItem, use their vid and find them inside the lambda. CEventFunctionHandler::instance().AddEvent([this](SArgumentSupportImpl*) { this->SendNotificationToAll(); }, "MY_BEAUTIFUL_EVENT", std::chrono::seconds(5).count() ); // Create the event and loop it every 5 minutes. Don't forget, keys already existing will be skipped, such as this one. CEventFunctionHandler::instance().AddEvent([this](SArgumentSupportImpl*) { this->SendNotificationToAll(); }, "MY_BEAUTIFUL_EVENT", std::chrono::minutes(5).count(), true ); // Check if it exists, then delay it again by 5s. Don't forget, DelayEvent has no effect to looped events. if (CEventFunctionHandler::instance().FindEvent("MY_BEAUTIFUL_EVENT")) CEventFunctionHandler::Instance().DelayEvent("MY_BEAUTIFUL_EVENT", std::chrono::seconds(5).count()); // Cancel the event. Safe even if the key doesn't exist. CEventFunctionHandler::Instance().RemoveEvent("MY_BEAUTIFUL_EVENT");
- 22 replies
-
- 55
-
-
-
-
-
-
If you're using cython, you can directly remove that function. RunFile isn't used elsewhere except for calling system.py. #ifdef __USE_CYTHON__ if (!pyLauncher.RunLine("import rootlib\nrootlib.moduleImport('system')")) #else if (!pyLauncher.RunFile("system.py")) #endif Just wrap the two functions like this: Why not? They are using c string allocation instead of std::string in the function calling it. It's not that hard to understand they were as dumb as monkeys. bool CPythonLauncher::RunFile(const char* c_szFileName) const { char* acBufData= nullptr; DWORD dwBufSize=0; { CMappedFile file; const VOID* pvData; CEterPackManager::Instance().Get(file, c_szFileName, &pvData); dwBufSize=file.Size(); if (dwBufSize==0) return false; acBufData=new char[dwBufSize]; memcpy(acBufData, pvData, dwBufSize); } bool ret=false; ret=RunMemoryTextFile(c_szFileName, dwBufSize, acBufData); delete [] acBufData; return ret; } Re-written: bool CPythonLauncher::RunFile(const char* c_szFileName) const { std::string acBufData; { CMappedFile file; const VOID* pvData; CEterPackManager::Instance().Get(file, c_szFileName, &pvData); if (file.Size() == 0) return false; acBufData.resize(file.Size()); memcpy(acBufData.data(), pvData, acBufData.size()); } return RunMemoryTextFile(c_szFileName, acBufData.size(), acBufData.data()); }
- 3 replies
-
- 12
-
-
-
-
-
-
You will get the dangling item pointer straight away (instead of dangling after calling M2_DESTROY_ITEM), but it won't cause a crash even if you use the item ptr immediately after SetCount(0), so you will not notice it (until the next tic). I mean, it can happen, but since the memory section doesn't get overwritten, it is very unlikely that it will happen: item->SetCount(0); // if non-owner count 0 items are internally deleted sys_err("You're not even getting a crash from %d %s even if deleted", item->GetID(), item->GetName()); Even ::UseItemEx suffers of this bug, but nobody noticed. LOG_MANAGER logs using dangling pointers for already 20 years. Only people using the public battlepass system actually get a crash there once in a while. ----------------------------------------------------------- Alternatively, you can call SaveSingleItem: (untested) else if(count == 0 && !m_pOwner) ITEM_MANAGER::instance().SaveSingleItem(this); It will delete the item immediately on the DB, so the other cores won't work on old cached items anymore. I expect that, since we're using TCP, and they can't login to another core until the previous one sends the logout packet, they can't easily bypass it via "lag" (also via client-side channel switch) as before. (tl;dr they must receive the item_destroy packet before the logout one) ----------------------------------------------------------- Otherwise, if you want to totally get rid of the dangling pointers that you could ever get, you need a quite long fix by using a smart pointer: Library: [Hidden Content] (the v3 is called cake::owner_ptr) Already tested on Live and 64bit. No lags, no instability. Used on CHARACTER, CItem, CObject, SECTREE, SECTREE_MAP, CDungeon, and so on. Example: LPITEM weapon = GetWear(WEAR_WEAPON); weapon->RemoveFromCharacter(); M2_DESTROY_ITEM(weapon); // if you use proxy_ptr, now weapon is nullptr instead of being a dangling item ptr sys_err("weapon ptr %p", weapon.get()); // 0
- 13 replies
-
- 41
-
-
-
-
-
-
Obviously the ones with count 0
-
You can bypass ch->CanWarp() by switching channels client-side though, so technically it can happen on regular servers as well. The best fix is inside CItem::SetCount by deleting non-owned items (with count 0 obviously) immediately, but you may have to solve some item ptr danglings afterwards. They often used the item ptr (like for logging) after using item->SetCount(0).
-
I made it via std::unique_ptr. Full Patch: diff --git a/asf_server/Srcs/Server/db/src/Main.cpp b/asf_server/Srcs/Server/db/src/Main.cpp index a34e7763..617040d5 100644 --- a/asf_server/Srcs/Server/db/src/Main.cpp +++ b/asf_server/Srcs/Server/db/src/Main.cpp @@ -105,7 +105,7 @@ int main() return 1; } -void emptybeat(LPHEART heart, int pulse) +void emptybeat(LPHEART & heart, int pulse) { if (!(pulse % heart->passes_per_sec)) { diff --git a/asf_server/Srcs/Server/game/src/main.cpp b/asf_server/Srcs/Server/game/src/main.cpp index 15f06e3d..5f6cfd69 100644 --- a/asf_server/Srcs/Server/game/src/main.cpp +++ b/asf_server/Srcs/Server/game/src/main.cpp @@ -208,7 +208,7 @@ namespace extern std::vector<TPlayerTable> g_vec_save; unsigned int save_idx = 0; -void heartbeat(LPHEART ht, int pulse) +void heartbeat(LPHEART & ht, int pulse) { DWORD t; diff --git a/asf_server/Srcs/Server/libthecore/include/heart.h b/asf_server/Srcs/Server/libthecore/include/heart.h index 45fb20f9..2feb6443 100644 --- a/asf_server/Srcs/Server/libthecore/include/heart.h +++ b/asf_server/Srcs/Server/libthecore/include/heart.h @@ -1,10 +1,11 @@ #ifndef __INC_LIBTHECORE_HEART_H__ #define __INC_LIBTHECORE_HEART_H__ +#include <memory> typedef struct heart HEART; -typedef struct heart * LPHEART; +using LPHEART = std::unique_ptr<heart>; -typedef void (*HEARTFUNC) (LPHEART heart, int pulse); +typedef void (*HEARTFUNC) (LPHEART & heart, int pulse); struct heart { @@ -19,8 +20,8 @@ struct heart }; extern LPHEART heart_new(int opt_usec, HEARTFUNC func); -extern void heart_delete(LPHEART ht); -extern int heart_idle(LPHEART ht); -extern void heart_beat(LPHEART ht, int pulses); +extern void heart_delete(LPHEART & ht); +extern int heart_idle(LPHEART & ht); +extern void heart_beat(LPHEART & ht, int pulses); #endif diff --git a/asf_server/Srcs/Server/libthecore/src/heart.c b/asf_server/Srcs/Server/libthecore/src/heart.c index 7316972b..13a36267 100644 --- a/asf_server/Srcs/Server/libthecore/src/heart.c +++ b/asf_server/Srcs/Server/libthecore/src/heart.c @@ -6,16 +6,13 @@ extern volatile int num_events_called; LPHEART heart_new(int opt_usec, HEARTFUNC func) { - LPHEART ht; - if (!func) { sys_err("no function defined"); return nullptr; } - CREATE(ht, HEART, 1); - + auto ht = std::make_unique<heart>(); ht->func = func; ht->opt_time.tv_sec = 0; ht->opt_time.tv_usec = opt_usec; @@ -27,10 +24,10 @@ LPHEART heart_new(int opt_usec, HEARTFUNC func) void heart_delete(LPHEART ht) { - free(ht); + ht.reset(); } -int heart_idle(LPHEART ht) +int heart_idle(LPHEART & ht) { struct timeval now, process_time, timeout, temp_time; int missed_pulse;
-
[Bug on all servers] How to fix this?
martysama0134 replied to HFWhite's topic in Community Support - Questions & Answers
>bunch of kids >not using IsEmptyItemGrid >recreating IsEmptyItemGrid code but uglier -
[Bug on all servers] How to fix this?
martysama0134 replied to HFWhite's topic in Community Support - Questions & Answers
If you have this bug server-side, then you must use IsEmptyItemGrid inside CHARACTER::MoveItem. GetItem returns nullptr in the 2nd/3rd vertical slot, that's why it fails. By default, many systems only check the grids client-side. -
[Python] Avoid closing client on have missing locales
martysama0134 replied to ZentraX's topic in Programming & Development
I don't think there are other alternatives than using a class(object) in python2. I've edited the code for supporting cython and uiscriptlocale as well: class LocaleInfoWrapper(object): def __init__(self, wrapped): self.wrapped = wrapped def __getattr__(self, name): try: return getattr(self.wrapped, name) except AttributeError: dbg.TraceError("Locale attribute not found: {}".format(name)) return name def __hybrid_import(name,globals=None,locals=None,fromlist=None, level=-1): if __USE_CYTHON__ and rootlib.isExist(name): if name in sys.modules: dbg.Tracen('importing from sys.modules %s' % name) return sys.modules[name] dbg.Tracen('importing from rootlib %s' % name) newmodule = rootlib.moduleImport(name) module_do(newmodule) if name.lower() in ("localeinfo", "uiscriptlocale"): newmodule = LocaleInfoWrapper(newmodule) sys.modules[name] = newmodule return newmodule else: filename = name + '.py' if pack.Exist(filename): if name in sys.modules: dbg.Tracen('importing from sys.modules %s' % name) return sys.modules[name] dbg.Tracen('importing from pack %s' % name) newmodule = _process_result(compile(pack_file(filename,'r').read(),filename,'exec'),name) module_do(newmodule) if name.lower() in ("localeinfo", "uiscriptlocale"): newmodule = LocaleInfoWrapper(newmodule) sys.modules[name] = newmodule return newmodule else: dbg.Tracen('importing from lib %s' % name) return old_import(name,globals,locals,fromlist)#, level) I'm also returning directly 'name' if not found. -
Problem with unequip costume
martysama0134 replied to Jimmermania's topic in Community Support - Questions & Answers
GetOriginalPart() check if you're using it properly in item.cpp -
official SungmaHee Tower Official Servers (C++, Python)
martysama0134 replied to Rakancito's topic in Features & Metin2 Systems
I gave a quick glance to your system, and I found a potential issue I reported some time ago to another c++ dungeon: Directly storing the character ptr in the dungeon instance is one of the main reasons for instability. You should use a function like this: LPCHARACTER FindValidCharacter(const VID & vid) { if (!vid.GetID()) return nullptr; const auto ch = CHARACTER_MANAGER::instance().Find(vid.GetID()); return (ch && !ch->IsDead()) ? ch : nullptr; } ------------------------------------------------------------------------- The reason why I write dungeons in LUA, and functionality in C++ is because: The whole lua environment works fine out of the box I can delegate quick edits to other people who have little to no knowledge It's incredibly easy to crash the whole process in a c++ dungeon, in comparison to lua People don't know how to correctly manage memory in c++, so it would have been better if they sticked to a simpler already-managed environment The maintenance of a c++ dungeon gets incredibly tiresome, in comparison to lua ------------------------------------------------------------------------- I also suggest you to never use magic numbers like [8][2], and to stick with std::array & an enumeration list to prevent repeated code like this: ------------------------------------------------------------------------- Thanks for sharing. -
Time back after reboot
martysama0134 replied to DarkFire's topic in Community Support - Questions & Answers
"reboot" now is "shutdown -r now". They changed the behavior in the last 7 years ?