Jump to content

AlGhoul

Community
  • Content Count

    138
  • Joined

  • Last visited

  • Days Won

    16

Everything posted by AlGhoul

  1. This is been addressed here: Also I think this is the wrong section.
  2. It is indeed a client side issue, I've described it earlier, there: Anywho, lemme put it in detail this time: Well, there's a CRC skills check that happens on the client, the CRC is usually performed on the server and the client just merely verifies it and the issue lies in the following statement "sometimes the CRC is not being sent, to be more accurate on some types and/or specific skills", I haven't investigated which skills are exceptions for that, but, I've investigated the CRC check problem (in fact it is a garbage variable problem) and I'll describe it to you now. In a struct called stNetNotiSkillEffect (I guess the name should ring a bell), there's a variable called SSrcState, to be specific it's defined in NetProtocol.h Line 120, another issue lies here (There's no constructor that initializes any of these variables declared here), Let's trace where that struct is being used: In NetIF.cpp Line 60, you'll find that SC_CharacterAction (RPC function) is being called to notify the client with actions that are being performed, SC_CharacterAction is defined in PacketCmd_SC.cpp Line 692 (this is quite a big function/procedure, that's quite convenient since it's an RPC & usually they have to handle many different cases), if you scrolled down a bit, you'll find the only case (PacketCmd_SC.cpp L850) that handles/fills the sSrcState variable is enumACTION_SKILL_TAR (and it does that in a specific sub-branch), here PacketCmd_SC.cpp Line 914, Now with that said, if you scrolled down a bit you'll find a call to NetActorSkillEff with the SSkillInfo struct being passed as the second argument (PacketCmd_SC.cpp Line 975), umm I wonder what that function does... Let's follow. NetActorSkillEff is defined @ NetProtocol.cpp Line 937, wonderful where's the issue? Check this branch: NetProtocol.cpp from Line 1044 to Line 1066, alright, the issue lies here: if( SkillEff.SSrcEffect.GetCount()>0 || SkillEff.SSrcState.GetCount()>0 || (SkillEff.sSrcState & enumFSTATE_DIE) ) // This is it --> (SkillEff.sSrcState & enumFSTATE_DIE) The sSrcState variable is being and-ed (Well if there's such a word, however this refers to the bitwise AND op) with enumFSTATE_DIE which is declared in the Common lib @ CompCommand.h Line 162, so what's up with it? what's the issue here? I'll tell you in a second but I've to still show that this branch and if that "and operation" succeeds (which is the case and the culprit for the issue), there's a sub-branch @ NetProtocol.cpp from Line 1057 to Line 1060 which handles self-performed skills (I noticed that death is mostly happening on skills like berserk or buffs (self-performed buffs) "skills & not notes or other ways of buffing") there's a death that is being applied on the targeted character and if you follow, this is a client side only effect. The whole issue is that, sSrcState is not being explicitly initialized, by the time sSrcState is checked (and when the server doesn't send any value for it) there could be anything in that variable, it was never initialized and might trigger that death and might not, depending on whatever garbage value that's left there before C++ taking over it's memory.
  3. The first Lua file that gets loaded after loading Lua libs, its dependencies and C API functions which are meant to be exposed to Lua, mentioned here in this function (method) BOOL CGameApp::Init(); which in turn calls InitLuaScript(); (which does what I described earlier), afterwards a call is made to this function LoadScript(); which calls the following function: void ReloadLuaInit() { lua_dofile( g_pLuaState, GetResPath("script/initial.lua") ); } So the first loaded file is at script directory, called initial.lua; I suggest that you load your hooks, globally needed functions, vars and definitions. With that said, I've seen some hooks and serializers that are not compatible with the recent versions of Lua (versions used in CO's for example), so double check them and use the correct ones depending on your Lua's version (meaning use older hooks/serializers if you are using an older version of lua).
  4. This happens due to a CRC check failure, AFAIK that the variable wasn't initialized and for some skills the server doesn't send anything , when the client do the checks, you get whatever garbage value that was in memory and the client/server thinks u are malicious, I couldn't find how classes' variables behavior were in C++03 but what I'm sure of is that unless you initialize ur variable in modern C++, you get whatever was leftover in that memory.
  5. Describe What do you mean by 'customize', also What do you mean by 'Part of Donate to be able to spend in my country'?
  6. This means that 'GetPetUreLV' doesn't exist, you should opt-out calling the function by deleting all the calls associated. for faster searching (If you are not using some of these tools already) you can use either VS Code or Notepad++; Notepad++ is even better searching directories and list of files for a specific content, however VS Code is sufficient if you are searching in a project/folder that's already open in your workspace. &misreload is reloading some files, also any files that are loaded with 'dofile' function are reloaded with them; so any plugins/extensions are also reloaded, if you are not checking for already initialized tables and/or data, you will be re-initializing them which would cause problems in many cases. Unfortunately many public extensions are poorly written and don't have any initialization checking.
  7. What are you using to host them? XAMPP, Nginx, etc? Have you checked your error logs? like C:\xampp\apache\logs\error.log?
  8. I agree that XAMPP/Zend are PHP engines, however Nginx can do much more, it could be used with python based websites with uWSGI and other solutions out there.
  9. You mean on managed hosting? No. and you don't really have any 'public' variations, all websites are the same except vector's. I've a private python website that is based on django framework I just roll it with a docker image.
  10. Are you kidding me? Anyone can create an installer easily.
  11. The 3 major maps should not be run with one another in one instance, while you can do so, it's not recommended. Running multiple GameServers allows scaling but it comes with it's cost, the infamous Dupe bug and that happens due to unsynchronized writes to the inventory/bank/temp bag(s) between two GameServers Example: Moving from 'garner' (Argent City) that runs on GameServer "A" to 'magicsea' (Shaitan City) that runs on GameSever "B" involves moving character's data to the new GameServer A -> B ; So you'll need a good AntiDupe. LUA solutions mitigate this but it can never prevent it entirely, A sudden restart/crash might result in duplicated items or roll backs.
  12. This is mostly cause of ur recorded spawn, unless you map "Argent City" coords/map to the new map along with its coords, u will respawn in ur last recorded spawn; You either have to map it as I mentioned earlier or update the recorded spawn for ur char.
  13. AlGhoul

    SourceCode Kop135

    @Unknown tried using a Chinese VPN or something?
  14. If you know the basics of python, you can copy any character's inventory and play with the following script until u grasp it, or atleast remove ur desired item. However This is an ancient script I wrote in python for my old django based PKO site, I'd re-write it if I were to use it in a similar context. It could be used as a base and I can see a room for extension as well. this one supported CO's inventory however the item string could be altered cause the script is "inventory agnostic", here is an example for an inventory item string itemString = f"ITEMSLOT, {item.itemID}, {item.quantity}, {item.durability}, {item.durability}, {item.energy}, {item.energy}, 0, {itemLocked}, {item.levelRequired}, 0, {forgeAttr}, {item.effectiveness}" import re import ctypes import struct """A class that represents TOP/PKO character's inventory and provides an easy API to interact with it. By AG/AlGhoul, Kind regards. Discord: AlGhoul#9988""" class Inventory: """Used to represent Character's Inventory""" _key = "19800216" _loaded = False def __init__(self, inventoryData: str): """Splits the inventory string and Initializes the object with the required vars""" self.invMaxSize, self.version, self.currentInventory = re.split( "[@#]", inventoryData, 3) def _decrypt(self, key: int = _key): """Decrypts Char's inventory DB string to normal comma separated numbers""" buffer = '' for charIndex in range(len(self.currentInventory)): buffer += chr(ord(self.currentInventory[charIndex] ) - ord(str(key[charIndex % 8]))) self._loaded = True self.currentInventory = buffer def _encrypt(self, key: int = _key): """Encrypts Char's inventory from normal comma separated numbers to a DB string""" buffer = '' for charIndex in range(len(self.currentInventory)): buffer += chr(ord(self.currentInventory[charIndex] ) + ord(str(key[charIndex % 8]))) self.currentInventory = buffer def _load(self): """Loads Char's inventory and dumps its data""" self._decrypt() self._temp = self.currentInventory.split(';') self._tempLength = len(self._temp) self.invItems = [self._temp[itemIndex] for itemIndex in range( self._tempLength) if itemIndex > 1 and itemIndex != self._tempLength - 1] self.invItemLength = len(self.invItems) self.invType = self._temp[0] self.occupiedSlotCount = int(self._temp[1]) self.currentCRC = int(self._temp[self._tempLength - 1]) self._loaded = True def calculateCRC(self): """Calculates/Validates 'Cyclic Redundancy Check' 'Checksum' for the current decrypted inventory""" self.newCRC = int(self.invType) for itemIndex in range(self.invItemLength): if not self.invItems[itemIndex]: continue item = self.invItems[itemIndex].split(',') for i in range(len(item)): if i == 0 or i == 7 or i == 10 or i == 13: continue itemAttr = int(item[i]) if i == 11: if itemAttr > 0: itemAttr = struct.unpack( 'l', struct.pack('L', itemAttr))[0] self.newCRC += itemAttr return ctypes.c_long(self.newCRC).value def addItem(self, itemString: str): """Adds normal item string in the first free slot in sight, returns False if failed or inventory is full, none on CRC mismatch""" if not itemString: return None if not self._loaded: self._load() if self.occupiedSlotCount > int(self.invMaxSize) - 1 or self.calculateCRC() != self.currentCRC: return False freeSlot = None for itemIndex in range(self.invItemLength): if itemIndex != int(self.invItems[itemIndex].split(',')[0]): freeSlot = itemIndex break if not freeSlot: return False itemString = itemString.replace('ITEMSLOT', str(freeSlot)) self.invItems.append(itemString) self.invItemLength = self.invItemLength + 1 self.currentInventory = '' for itemIndex in range(self.invItemLength): self.currentInventory += f"{self.invItems[itemIndex]};" self.currentInventory = f"{self.invType};{self.invItemLength};{self.currentInventory};{self.calculateCRC()}" return True def removeItem(self, itemID: int, amount: int): """"Removes an 'amount' of item(s), if amount is set to '-1' it removes the item entirely from all slots, returns false if not enough quantity, none on CRC mismatch""" if amount != -1 and self.GetItemCount(itemID) < amount: return False if not self._loaded: self._load() if self.calculateCRC() != self.currentCRC: return None itemIndexList = [] itemRemoveList = [] for itemIndex in range(self.invItemLength): if itemID == int(self.invItems[itemIndex].split(',')[1]): itemIndexList.append(itemIndex) itemRemoveList.append(self.invItems[itemIndex]) if not itemIndexList or not itemRemoveList: return None nextToRemove = 0 for i in range(len(itemIndexList)): if amount == -1: self.invItems[itemIndexList[i]] = None continue if nextToRemove == 0 and amount > int(self.invItems[itemIndexList[i]].split(',')[2]): nextToRemove = amount - \ int(self.invItems[itemIndexList[i]].split(',')[2]) del self.invItems[itemIndexList[i]] elif nextToRemove != 0: nextToRemove = int(self.invItems[itemIndexList[i]].split(',')[ 2]) - nextToRemove item = self.invItems[itemIndexList[i]].split(',') item[2] = nextToRemove modifiedItem = ','.join(map(str, item)) self.invItems[itemIndexList[i]] = modifiedItem break else: nextToRemove = int( self.invItems[itemIndexList[i]].split(',')[2]) - amount item = self.invItems[itemIndexList[i]].split(',') item[2] = nextToRemove modifiedItem = ','.join(map(str, item)) self.invItems[itemIndexList[i]] = modifiedItem self.currentInventory = '' self.invItemLength = len(self.invItems) for itemIndex in range(self.invItemLength): if self.invItems[itemIndex] == None: continue self.currentInventory += f"{self.invItems[itemIndex]};" self.currentInventory = f"{self.invType};{self.invItemLength};{self.currentInventory};{self.calculateCRC()}" return True def GetItemCount(self, itemID: int): """Gets a specific item's total count""" if not itemID: return 0 if not self._loaded: self._load() itemCount = 0 for itemIndex in range(self.invItemLength): if self.invItems[itemIndex] != None and itemID == int(self.invItems[itemIndex].split(',')[1]): itemCount += int(self.invItems[itemIndex].split(',')[2]) return itemCount def GetNewInventory(self): """Returns a new encrypted inventory, ready to be written into the DB""" self._encrypt() return f"{self.invMaxSize}@{self.version}#{self.currentInventory}"
  15. I know the process, thanks for the info. I didn't really mention anything else other than a function pointer and that's a fact. Anything else like accessing Vars and Functions, it's not that easy for beginners, but still it's not that hard when it comes to counting some bytes, is it? The hard part is debugging for some people and the overall process is time consuming tbh. I'm not underestimating your work though so it's nothing personal I'm just stating some facts, thanks for understanding.
  16. Hello @Hobbiest and welcome! I don't know what do u mean by "OG" but I'm assuming u are talking about PKO's models, u can convert them in 3ds max and use them anywhere. For this you need C/C++, LUA/SQL aren't a big deal you can learn them along the way. C++/Detours, it's not that hard to grab a function pointer from any legacy EXE especially the ones with pdb. The more you learn, the more it'll become intuitive, most of these topics are mentioned almost everywhere especially in low-level stuff. Both, some Spanish/Brazilian kids are showing off and some are creating them for money You can create it on unity and all good, you have to keep networking on mind from day one most of these aren't really MMO friendly networking architecture the only thing I'd say that was good regarding TOP/PKO is their networking architecture I'm not talking about the ServerSDK or how they implemented the networking but I'm talking about the separation of concerns; 1- GateServer is acting like a proxy 2- AccountServer is validation logins for less tension on the server they even separated the login database (AccountServerDB) 3- GroupServer is handling Chat/Guilds/Teams (Partying and whatnot) 4- GameServer is handling the gamestate, hence you can scale the server by spawning more GameServers the only issue I can tell so far about this is the Data Race when player moves between instances (hence the infamous items duplication bug) You can learn alot reading from unreal's docs networking docs and not just networking by the way: https://docs.unrealengine.com/udk/Three/NetworkingOverview.html Good luck.
  17. AttrCalculate.lua -> BsAttrUpgrade function
  18. Of course it is, there's no limit. If you need some help regarding this, post your Reb NPC function.
  19. This is just a name that you can replace, you should be concerned with the body of the function, you build up on it.
  20. Actually both, mostly players looking for new Servers and/or tweaks.
  21. function IsSkySet( role ) local Atk = IsPlayer ( role ) local boat = ChaIsBoat ( role ) if Atk == 0 or boat == 1 then return 0 end local head = GetChaItem ( role , 1 , 0 ) local body = GetChaItem ( role , 1 , 2 ) local hand = GetChaItem ( role , 1 , 3 ) local foot = GetChaItem ( role , 1 , 4 ) local Head_ID = GetItemID ( head ) local Body_ID = GetItemID ( body ) local Hand_ID = GetItemID ( hand ) local Foot_ID = GetItemID ( foot ) local FusedBody_ID = GetItemAttr ( body , ITEMATTR_VAL_FUSIONID ) local FusedHand_ID = GetItemAttr ( hand , ITEMATTR_VAL_FUSIONID ) local FusedFoot_ID = GetItemAttr ( foot , ITEMATTR_VAL_FUSIONID ) -- local hasSkyStone = CheckBagItem( role, 7529) -- if (Body_ID ~= idToBeChecked or Hand_ID ~= idToBeChecked or Foot_ID ~= idToBeChecked) then return 0 end if (FusedBody_ID ~= 24 or FusedHand_ID ~= 25 or FusedFoot_ID ~= 26) then return 0 end -- if hasSkyStone ~= 1 then -- return 0 -- end return 1 end Here you go, I used this in Avacado Online, the normal (nonfuse) checks are commented but I kept them for convenience plus you can enable the hasSkyStone in-order to check for a fused set + a stone to have stun effect but don't enable it in place, you can add it to the fuse checks as an (or hasSkyStone ~= 1) also if you gonna use this function notice it returns false for mismatches, true otherwise so you have to check for either of the predictable conditions and beware of mismatches in lua, you have to explicitly check for a success local hasSkySet = IsSkySet(Player) if hasSkySet == 1 then -- perform something end because of the following Implicit checks like the following example, are error prone and mostly won't work. local hasSkySet = IsSkySet(Player) if hasSkySet then -- perform something end
  22. Pages could be extended, it is just a matter of changing a var
  23. There's a c_pay_tb table that's missing from ur GameDB, the question is did u build this from src or bought it from someone? Whatever ur answer is, u should either contact the dev or just check ur src.
  24. Of course it will NOT, You have to include your decryption in your MindPower3D -- Why would you assume that your client is going to assume your decryption algorithm outta nowhere and use it?
×
×
  • Create New...