Jump to content

Karbust

Management
  • Posts

    1161
  • Joined

  • Days Won

    10
  • Feedback

    100%

Everything posted by Karbust

  1. Without those changes: [Hidden Content] With those changes: [Hidden Content] Code used (with it false that weird flying bug doesn't happen): GCL::Importer::GrannyImportOptions options; options.importAnimationDeboor = true; GrannyImporter* importer = new GrannyImporter(options); I attempted to apply that update to see if it would solve the left shoulder issue, but apparently it didn't. To fix it manually just need to mirror Bone_shoulder_03 on XY axis and adjust the position manually.
  2. GitHub: [Hidden Content] => (or Metin2 Download) This tutorial is also available on the GitHub repo. Metin2-InfluxDB The purpose of this is to be able to create dashboards with the timeseries statistics, like the ones seen on the video made with Grafana. Install InfluxDB: [Hidden Content] Information If you intend on using Cloudflare (and nginx as reverse proxy, since InfluxDB’s default port is 8086, which isn’t supported by Cloudflare, if you choose the docker installation, just map it to a port supported by Cloudflare, preferably HTTPS), you will need to create a firewall exception to bypass all rules that come from your metin2 game server so it doesn’t get blocked or challenged. I recommend setting up nginx as reverse proxy, that way the port 443 can be used for all hosts configured on nginx. On FreeBSD, only InfluxDB 1.8.* is available, not recommended, since the latest major stable version is 2.1. This tutorial was made for version 2.1, there may be differences on the requests. An IP address can be used, but a domain with SSL setup is preferable, for obvious reasons. InfluxDB Setup Create an organization Create a bucket Lib cURL FreeBSD Setup Install it: pkg install curl And link it on the Makefile: -lcurl Windows Setup For Windows it works with both vcpkg and compiling the lib manually. Shared lib: vcpkg install curl[openssl]:x86-windows Static lib: vcpkg install curl[openssl]:x86-windows-static Auto Event Manager In case you already have this class/file, just compare and make the necessary changes. All the changes related to Influx are wrapped with the macro INFLUX_STATS. Don't forget to also make the necessary changes on main.cpp. If you are already using this you won't need to include the header and initialize the class. Edit Time The default is send the data every 10 minutes. On the file InfluxData.cpp, edit this code: void CInfluxData::Check(int day, int hour, int minute, int second) { int lastNumber = minute % 10; if (isInfluxEnabled && lastNumber == 0 && second == 00) If lastNumber = 0, then it means the number is divisible by, in this case, 10. Make sure when you edit the time to don't forget the seconds part, if you don't use it, it will run every second inside the minute you want to run it. Examples for other times Every minute if (isInfluxEnabled && second == 00) Every 5 minutes int lastNumber = minute % 5; Every 30 seconds int lastNumber = seconds % 30; if (isInfluxEnabled && lastNumber == 0) Configuration To use this make sure you have it only enabled on ONE core per channel, the online counter inside the channel is common between the cores, just add this on the CONFIG file to enable Influx on the core. INFLUX_ENABLE: 1 The rest of the settings, can either be set on the source or by CONFIG options (this are the default values set on the source): INFLUX_URL: [Hidden Content] INFLUX_TOKEN: <token> INFLUX_ORG: <organization> INFLUX_BUCKET: <bucket> NodeJS Version In case you don't to use the source, a NodeJS version is available where you can use the Metin2 API to get the user count and send it to Influx. The source method is preferred. Acknowledgments: Gurgarath for testing the tutorial on Windows. Deliris for testing the tutorial on FreeBSD.
  3. My customized patcher services are closed until further notice due to lack of time. All the clients that already paid and I haven't finished are still going to get the work in full. I will also be available to clients that are still within my support timeframe. The base premium patcher is still available for purchase. Only custom works are closed at the moment. Hello bois, grils and everything in between Today I started offering my services, right now I will only be doing custom patchers. The patchers will have a improved version of my open-source work (using React, Typescript and Electron): What is better/new? Self-update Ability to delete files Ability to ignore files (download if not exist, otherwise ignore) Throttle download speed Windows progress bar on taskbar and flashing on finish Ability to check if the client binary is running and not open the patcher Ability to limit the amount of times the client binary can be opened Better optimization on downloads and resources consumption Overall dependencies updated (included Electron) My support The patcher sold after 2024-03-18 no longer runs on Windows 7, 8 and 8.1 due to updating the Electron dependency. I will not give any support for those Operating Systems. Read point 14 on the Terms of Customer Service below. The base price is 100€ (only the features specified above). Custom services can be requested and this category starts at 110€ and will include the base patcher described above. No UI overall changes (base design) and feature request starts at 115€ Overall UI change (with PSD/Figma (You bring your design, I have no design skills)) and features request starts at 175€ Custom tools: Upload tool for SFTP and FTP (Made in C#) - 30€ Upload tool for Cloudflare R2 (or other S3 compatible storages) (Made in C#) - 30€ Other custom tools - per request Since my time is limited, I will not accept more than 1 or 2 custom projects at a time. For complex custom projects, expect at least 1 week to have it ready (emphasis on at least). Code signing is currently supported. Signings are made automatically through a pipeline. My current certificate is valid until 2027/01/08. Starting at January 20th 2023 new customers have the possibility to have their patchers digitally signed with my own Code Signing Certificate. This is only valid for patchers built by me, you cannot make changes after it is compiled (if you make changes in the source and recompile it the file will not be signed) (this process is now automated by a pipeline). This service adds a flat fee of 50€ on top of the prices specified above (this is only valid for the duration of the support, check the length of support on the rules below, after that you can renew for 6 extra months at the same price). For more information check out this page https://sectigo.com/resource-library/what-is-code-signing If you want to get in contact with me and we don't share any server, join my discord server at: https://karbu.st/discord In the future more services can appear but, for now, this is it
  4. Did you buy it from him? Because it's not free on his website. We don't support leaked content.
  5. For now, I only have it enabled on groups. I'm also working on an implementation that would allow the users to enable voice on an entire map, like a commerce map, or whatever. Users can mute/unmute themselves. Push-To-Talk will also be possible.
  6. Karbust

    Voice Ingame

    I'm doing a system that offers voice ingame, it is almost done. Would anyone consider buying a system that would offer Voice Ingame? Leave your feedback please. Thank you
  7. Sup guys DISCLAIMER: The code on this topic of only useful if have done changes to the Pet System (like putting it on the slot) and/or use the Mount System that follows the character if you have it on a slot. The code for the horse is valid for everyone. This code was done by @ Mali and he asked me to share it. This code is to fix a bug on observer mode, like guild wars. If you have a pet on the slot and it respawns every time you teleport, this affects you. If you have a mount on the slot and it respawns every time you teleport, this affects you. If you only have the mount following you and you unmount while on observer, it will affect you. This last one is also valid of the horse. The bug consists on having any of the points described above which will make the pet, mount or horse visible to everyone when the player is in observer mode. Something like this (the player Faisca is the observer on a guild war): Let's start Open char_horse.cpp, and after: Add: Open PetSystem.cpp Search for: And make it like this: Search for: Add after: At the end of the file add this: Open PetSystem.h, and after: Add: Open entity.cpp Inside this function: Change it like this: You are finished if you don't use a special mount system. Now, if you have the file MountSystem.cpp, open it, and search for: And edit like this: Search for: Add after: At the end of the file add this: Open MountSystem.h, and after: Add: Then edit entity.cpp again like this: And your are finished. Thanks again to @ Mali for helping me solve this issue.
  8. No one should face fear when starting, we all start somewhere, sometimes is just trial and error. I read a lot of blog entries (mostly all on medium) and documentation for something I'm learning or trying to achieve or trying to compare to alternatives and see which one is the most performant and/or more secure. I have a lot of books, some which I have personally used for both college and personal projects, you can find them here: [Hidden Content]
  9. SQL Injection, bad handling of sessions and/or authentication cookies/tokens, remote code execution If you don't sanitize every single thing you get from the frontend and it's supposed to end up in a database, then you are open to the risk of SQL Injection. I recommend the use of ORMs, since it already handles almost all the boring part of sanitizing input. If you don't write good code and end up doing some sketchy shit that executes commands on the server running the website, then your are fucked... Authentication is some of the hard parts of doing a good website, there are discussions on where should the information be saved, either cookies or local storage and manually attach it to every request. I work with JWT, and I always put the token on cookies so it goes attached to every request when CORS with Allow Credentials set to true. Also make sure you use strict true so it doesn't go on requests to other domains. Obviously cookies can be grabbed by some third party trick, but it's hard and if you put a expire date on JWT and use refresh tokens and IP validation, then you are better served.
  10. account.account can have insert, select and update, not only to email and password like you referenced. player.guild only select player.player can have select and update (in case you have an unbug function, otherwise only select) player.item or player.item_award only insert, depending on which table you use Other tables related to item shop and purchases should have, at least, insert and select
  11. Sashes base item vnum is fixed in the binary source, starting at 85000. Use and ID after the last basic sash and check if it works.
  12. Yes to both questions. For the first you need to make changes in the source, somewhere in input_login, maybe, never did it. For the second, assuming you are doing it in PHP, I have no idea how to do it, just search for route rate limit in php on google. In NodeJS (ExpressJS or others) would be a lot easier.
  13. I'm having an issue with this and I have no idea what is causing it... This is what I was able to gather, the issue is coming from this lines: [Hidden Content]. Svn/Server/db/ClientManager.cpp#L45-L59 I put the code like this: DWORD dwSocket2 = pItemAward->dwSocket2; sys_err("Socket2 0: %u", dwSocket2); sys_err("bType: %d", pItemTable->bType); sys_err("bSubType: %d", pItemTable->bSubType); if (pItemTable->bType == ITEM_UNIQUE) { #ifdef ENABLE_EXTEND_ITEM_AWARD // 12.04.2019 - Correction for unique items based on the real time. const long lValue0 = pItemTable->alValues[ITEM_SOCKET_REMAIN_SEC]; const long lValue2 = pItemTable->alValues[ITEM_SOCKET_UNIQUE_REMAIN_TIME]; const time_t tNow = CClientManager::instance().GetCurrentTime(); dwSocket2 = (lValue2 == 0) ? static_cast<DWORD>(lValue0) : static_cast<DWORD>(tNow + lValue0); sys_err("Socket2 1: %u", dwSocket2); #else if (pItemAward->dwSocket2 != 0) dwSocket2 = pItemAward->dwSocket2; else dwSocket2 = pItemTable->alValues[0]; #endif } And this is the output: SYSERR: Jan 14 20:31:34 :: RESULT_SAFEBOX_LOAD: Socket2 0: 28435 SYSERR: Jan 14 20:31:34 :: RESULT_SAFEBOX_LOAD: bType: 16 SYSERR: Jan 14 20:31:34 :: RESULT_SAFEBOX_LOAD: bSubType: 2 SYSERR: Jan 14 20:31:34 :: RESULT_SAFEBOX_LOAD: Socket2 1: 180 SYSERR: Jan 14 20:31:34 :: RESULT_SAFEBOX_LOAD: Query: INSERT INTO item (id, owner_id, item.window, pos, vnum, count, socket0, socket1, socket2, attrtype0, attrvalue0, attrtype1, attrvalue1, attrtype2, attrvalue2, attrtype3, attrvalue3, attrtype4, attrvalue4, attrtype5, attrvalue5, attrtype6, attrvalue6) VALUES(2000000012, 1, 'MALL', 1, 61096, 1, 28433, 28434, 180, 72, 65, 71, 30, 5, 12, 9, 20, 12, 8, 0, 0, 0, 0) This is the proto of that item: 61096 LaminaXPTO ITEM_WEAPON WEAPON_TWO_HANDED 3 ANTI_ASSASSIN | ANTI_SURA | ANTI_MUDANG | ANTI_DROP | ANTI_SELL ITEM_TUNABLE WEAR_WEAPON NONE 0 0 0 0 15 LEVEL 240 LIMIT_NONE 0 APPLY_ATT_SPEED 65 APPLY_ATTBONUS_HUMAN 55 APPLY_CRITICAL_PCT 50 0 550 650 600 700 70 0 3 -1 This is what I used to create it: INSERT INTO `player`.`item_award` (`login`, `vnum`, `count`, `socket0`, `socket1`, `socket2`, `attrtype0`, `attrvalue0`, `attrtype1`, `attrvalue1`, `attrtype2`, `attrvalue2`, `attrtype3`, `attrvalue3`, `attrtype4`, `attrvalue4`, `mall`) VALUES ( 'admin', -- LOGIN 61096, -- ITEM ID 1, -- COUNT 28433, 28434, 28435, -- SLOTS 72, 65, -- DM 71, 30, -- DH, 5, 12, -- APPLY_STR 9, 20, -- APPLY_CAST_SPEED 12, 8, -- APPLY_POISON_PCT 1 -- LOCATION ); This is the result on item_award: id pid login vnum count given_time taken_time item_id why socket0 socket1 socket2 socket3 socket4 socket5 attrtype0 attrvalue0 attrtype1 attrvalue1 attrtype2 attrvalue2 attrtype3 attrvalue3 attrtype4 attrvalue4 attrtype5 attrvalue5 attrtype6 attrvalue6 mall 19 0 admin 61096 1 1000-01-01 00:00:00 28433 28434 28435 0 0 0 72 65 71 30 5 12 9 20 12 8 0 0 0 0 1 And this is what I get when I open the mall: id owner_id window pos count vnum transmutation socket0 socket1 socket2 socket3 socket4 socket5 attrtype0 attrvalue0 attrtype1 attrvalue1 attrtype2 attrvalue2 attrtype3 attrvalue3 attrtype4 attrvalue4 attrtype5 attrvalue5 attrtype6 attrvalue6 2000000012 1 MALL 1 1 61096 0 28433 28434 180 0 0 0 72 65 71 30 5 12 9 20 12 8 0 0 0 0 The Socket2 is getting fucked up and I have no clue why. I have no idea how the item type is being assumed as ITEM_UNIQUE. Anyone has any idea on how to solve it? For some reason the same db works on my other server and this issue doesn't happen, the only difference is the mysql database. Thank you Related to my problem from above, and thanks to @ Abel(Tiger) for sending me this post by him: This particular problem has been solved, but more issues arose. First, if I added 3 stones, the 1st and 2nd slot would be set as 1 and only the 3rd would have a stone, that issue has been fixed by changing void ItemAwardManager::CheckItemSocket function's body to this: void ItemAwardManager::CheckItemSocket(TItemAward & rkItemAward, const TItemTable & rkItemTable) { // check for limited time items auto hasTimeLimit = false; for (size_t i = 0 ; i < ITEM_LIMIT_MAX_NUM && !hasTimeLimit; i++) { if (LIMIT_REAL_TIME == rkItemTable.aLimits[i].bType || LIMIT_REAL_TIME_START_FIRST_USE == rkItemTable.aLimits[i].bType) hasTimeLimit = true; } // check slottable sockets for non limited time items const auto maxSockets = std::min<int>(rkItemTable.bGainSocketPct, ITEM_SOCKET_MAX_NUM); if (maxSockets <= 0 || hasTimeLimit) return; //This if's have been changed to check if the socket* is 0, and only then set it to 1 if (maxSockets >= 1 && rkItemAward.dwSocket0 == 0) rkItemAward.dwSocket0 = 1; if (maxSockets >= 2 && rkItemAward.dwSocket1 == 0) rkItemAward.dwSocket1 = 1; if (maxSockets >= 3 && rkItemAward.dwSocket2 == 0) rkItemAward.dwSocket2 = 1; } Then another problem presented itself, if I set socket2 as 0, it wouldn't be changed to 1 on the function above, because it would edit the value on pItemTable and not on the variable dwSocket2 that is used on the query. This issue was fixed by changing this: //Change the function call with this: ItemAwardManager::instance().CheckItemSocket(*pItemAward, *pItemTable, &dwSocket2); //Change the function header on ItemAwardManager.h with this: void CheckItemSocket(TItemAward & pkItemAward, const TItemTable & pkItemTable, DWORD *dwSocket2); //Change the function body with this: void ItemAwardManager::CheckItemSocket(TItemAward & rkItemAward, const TItemTable & rkItemTable, DWORD *dwSocket2) { // check for limited time items auto hasTimeLimit = false; for (size_t i = 0 ; i < ITEM_LIMIT_MAX_NUM && !hasTimeLimit; i++) { if (LIMIT_REAL_TIME == rkItemTable.aLimits[i].bType || LIMIT_REAL_TIME_START_FIRST_USE == rkItemTable.aLimits[i].bType) hasTimeLimit = true; } // check slottable sockets for non limited time items const auto maxSockets = std::min<int>(rkItemTable.bGainSocketPct, ITEM_SOCKET_MAX_NUM); if (maxSockets <= 0 || hasTimeLimit) return; if (maxSockets >= 1 && rkItemAward.dwSocket0 == 0) rkItemAward.dwSocket0 = 1; if (maxSockets >= 2 && rkItemAward.dwSocket1 == 0) rkItemAward.dwSocket1 = 1; if (maxSockets >= 3 && rkItemAward.dwSocket2 == 0) { rkItemAward.dwSocket2 = 1; *dwSocket2 = 1; } } Then another problem come up, ITEM_UNIQUE would always replace the value you set on socket2 by the default value of the item, and to fix this, just change: //This: if (pItemTable->bType == ITEM_UNIQUE) //With this: if (pItemTable->bType == ITEM_UNIQUE && pItemAward->dwSocket2 == 0) Hope this helps someone.
  14. Since not everyone has a good internet and there are instances when someone can have high ping, I think it shouldn't affect the game play capability in such cases, so I just added the ping code to a thread and now it doesn't block the game. [Hidden Content]
  15. With me it doesn't crash, but the window stays white for some reason...
  16. Seems like that lib isn't static (it's dynamic), which means it will require that the to be placed on the same folder as the executable. Ask the dev for the DLL. This anti-cheat is being sold on metin2dev:
  17. Did you add the path on the source? (The code on your last post.) Did you import npc3 on Index or on source? Did you replace the texture paths on the gr2 models with npc3?
  18. Auth and chanel's are going to be accessible by the player, it's useless changing them because they can get them anyway.
  19. The ones not blurred are on the official client: The rest is probably some proprietary models.
  20. At this point I can't decide if you are just trolling or your are dumb as f***. You are talking about the drivers INSIDE THE KERNEL that's no system or software or none of that shit you have been talking about. If you want to remove this you just remove them from the fucking KERNEL and build it yourself. This doesn't affect performance at all. Go ahead and report me for "bothering" your.
  21. Not sure what you are talking about, the screenshot I posted above is running on FreeBSD 13 and doesn't even reach 650MB of RAM and that's with 400MB of them being used by MySQL server...
  22. Update Added a slider component that can be enabled or disabled (enabled by default) (instructions on how to use it are available on the repository). Changed from CRA (Create-React-App aka react-scripts) to Vite, which allows for a faster development, build time and reduced package size. Also replaced the compression method from "maximum" to "normal", since there is no difference in sizes, but takes much less time to build. [Hidden Content]
  23. That's why I said for you to learn it, test it and then share the results.
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.