Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/20/18 in all areas

  1. As we work with maps we accumulate a large number of unused textures which end up making the client / pack downloads for our server bigger. For this reason I made this little python 2.7 script. It will read all the textureset files and the texture paths on it and copy to textureset_release/ only the textures that are actually being used by your maps, as listed in Settings.txt The folder where the script looks for Settings.txt files recursively is "maps/", change it at the start of the code if yours is different. Likewise, it will look for "textureset/" and "terrainmaps/", and create "textureset_release/". No files will be deleted. Disclaimer: The code is very ugly, I actually have no idea of python, I made this script looking at docs and based on my knowledge of other languages. If you actually know python I suggest you don't look at it to avoid hurting your eyes. import os import re import string import shutil import sys ct = 0 usedimg = [] usedsets = [] list = [] mapfolder = 'maps/' class cd: """Context manager for changing the current working directory""" def __init__(self, newPath): self.newPath = os.path.expanduser(newPath) def __enter__(self): self.savedPath = os.getcwd() os.chdir(self.newPath) def __exit__(self, etype, value, traceback): os.chdir(self.savedPath) def cleanValue(val): val = val.replace('\\', '/') val = val.strip(' \t\n"') val = val.lower() return val def copyFile(src, dest): try: shutil.copy(src, dest) # eg. src and dest are the same file except shutil.Error as e: print('Error: %s' % e) # eg. source or destination doesn't exist except IOError as e: print('Error: %s' % e.strerror) # Read the tab-separated value of a parameter "param" in all files named "fname" (can be an extension) in folder "folder" def SaveParams(param,fname,folder,list): for path, subdirs, files in os.walk(folder): for filename in files: if filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname)): f = os.path.join(path, filename) with open(f, "rt") as current: for line in current: lcline = line.lower() lcparam = param.lower() if lcparam in lcline: # strip tabs and split values value = line.rstrip('\t\n') # get parameter value list.append(value) # Read a value with the order number "order" within a parameter block "block" in all files named "fname" (can be an extension) in folder "folder" which are also in list "compare" def SaveParamsFromBlock(block,order,fname,folder,list,compare): for path, subdirs, files in os.walk(folder): for filename in files: if filename in compare and (filename.lower() == fname.lower() or (fname.startswith('.') and filename.endswith (fname))): countblock = -1 f = os.path.join(path, filename) with open(f, "rt") as current: for line in current: lcline = line.lower() lcblock = block.lower() if countblock == order: list.append(line) countblock = -1 elif lcline.startswith(lcblock): countblock = 0 elif countblock >= 0: countblock = countblock + 1 # move to the client data folder with cd('..\client\data'): try: os.makedirs('terrainmaps_release') except: shutil.rmtree('terrainmaps_release') os.makedirs('terrainmaps_release') print "This script copies to terrainmaps_release only the textures which are actually listed in textureset files." print "The folder is emptied on each run. make_archive.py uses this folder as source for making the terrainmaps pack." print "This script is written to be run from the tools repo copy and assumes the client repo copy to be in the same base directory as tools" print "" select = raw_input("Press any key to start, e to exit") if str(select) == "e": sys.exit() # Get all the texturesets used in our maps SaveParams('TextureSet','Setting.txt','maps',usedsets) # Extract the filename part of the used TextureSet paths and write it back to the list for idx,val in enumerate(usedsets): val = cleanValue(val) parts = re.split('/', val.lower()) # check its actually a terrainmaps path usedsets[idx] = parts[-1] # Fetch a list of the textures used in the sets used SaveParamsFromBlock('Start Texture',0,'.txt','textureset',usedimg,usedsets) # Copy the textures used in textureset_release for idx,val in enumerate(usedimg): # check its actually a terrainmaps path if "terrainmaps" in val: val = cleanValue(val) val = val[len('d:/ymir work/terrainmaps/'):] usedimg[idx] = val.lower() srcPath = 'terrainmaps/' + usedimg[idx] destPath = 'terrainmaps_release/' + usedimg[idx] print "Copy " + srcPath + " to " + destPath if not os.path.isdir(os.path.dirname(destPath)): os.makedirs(os.path.dirname(destPath)) copyFile(srcPath, destPath) ct = ct + 1 print "Total " + str(ct) + " textures copied in terrainmaps_release" raw_input("Press any key to exit") As a bonus another python 2.7 script used to create the property/list file with all your prb, pre. Assumes a property/ folder at the location where you run it. import os import math count = 0 extensions = ('prb','prt','prd','pre','pra') with open("property/list", "w") as a: for path, subdirs, files in os.walk(r'property'): for filename in files: f = os.path.join(path, filename) if filename != "list" and filename !="reserve": extension = filename.split ('.')[-1] if (extension in extensions): a.write(str(f) + '\n') else: Print ("Strange file: " + f) count = count + 1 print 'Total: ' + str(count) + ' files listed on property/list!' raw_input("Press any key to exit") And finally another script to copy all your msa and motlist.txt files to a server/data folder that you can upload later to your server. It will only copy when files are different or not existing at the destination. It assumes a ../client/data/npc (and so on) and ../server/data/monster etc. structure, feel free to edit the paths in the scripts to your needs. import os import shutil from itertools import chain import filecmp pathList = [] count = 0 def copyFile(src, dest): try: shutil.copy(src, dest) return True # eg. src and dest are the same file except shutil.Error as e: print('Error: %s' % e) # eg. source or destination doesn't exist except IOError as e: print('Error: %s' % e.strerror) print "This script moves all the .msa and motlist.txt files from pc monster and npc client folders to the appropiate server folders, creating them if necessary." paths = ('../client/data/monster/', '../client/data/monster2/', '../client/data/npc/', '../client/data/npc2/', '../client/data/pc/', '../client/data/pc2/') for path, dirs, files in chain.from_iterable(os.walk(path) for path in paths): for filename in files: if filename.endswith('.msa') or filename.endswith('.txt'): realpath = path.replace('\\', '/') cfolder = os.path.split(realpath)[1] gfolder = 'monster' if ('/pc/' in realpath): gfolder = 'pc/' + realpath.split('/')[4] elif ('/pc2/' in realpath): gfolder = 'pc2/' + realpath.split('/')[4] else: # Check for duplicated non-pc folders existingpath = next((s for s in pathList if ('/' + cfolder) in s), None) if existingpath and existingpath.endswith(cfolder): if realpath != existingpath: print("Warning: duplicate folders " + realpath + " and " + existingpath + "!") pathList.remove(existingpath) break elif path not in pathList: pathList.append(realpath) else: pathList.append(realpath) spath = realpath + '/' + filename dpath = '../server/data/' + gfolder + '/' + cfolder # Create destination folder if not existing if not os.path.isdir(dpath): os.makedirs(dpath) dpath = dpath + '/' + filename # Copy file if destination is not existing or different if not os.path.exists(dpath) or not filecmp.cmp(spath,dpath): if copyFile(spath, dpath): print "Copied " + spath + " to " + dpath count = count + 1 print "Finished copying " + str(count) + " files!" raw_input("Press any key to exit") How to use: install python 2.7 anywhere on your hd (C:\Python27 for example), add this path to the system path, and save this code in a file named something.py, then run it by doubleclick Remember to change directory to wherever you have your client files.
    1 point
  2. Guys, are you developing game or circus in past three years?
    1 point
  3. Hi, A few days ago I observed that horse level is missing from client. You are able to see the level only when you advance your horse or when you take with a command (for GMs). I don't know if somebody else have this bug, but I will post the little fix I found because you never know. In input_login.cpp, inside the function void CInputLogin::Entergame(LPDESC d, const char * data) look for if (ch->GetHorseLevel() > 0) { DWORD pid = ch->GetPlayerID(); if (pid != 0 && CHorseNameManager::instance().GetHorseName(pid) == NULL) db_clientdesc->DBPacket(HEADER_GD_REQ_HORSE_NAME, 0, &pid, sizeof(DWORD)); } And replace that check with this one if (ch->GetHorseLevel() > 0) { DWORD pid = ch->GetPlayerID(); if (pid != 0 && CHorseNameManager::instance().GetHorseName(pid) == NULL) db_clientdesc->DBPacket(HEADER_GD_REQ_HORSE_NAME, 0, &pid, sizeof(DWORD)); ch->SetHorseLevel(ch->GetHorseLevel()); ch->SkillLevelPacket(); } That's it. Enjoy.
    1 point
  4. Hi everyone, I don't know if there is already a solution, but if it is I couldn't find it and I am sorry. I will post a solution found by me today. How does actually this bug works? Well, when you enter in game you will not have anti-stun until you will change the equipment and if your shield or your anti-stun item is not last then you will still not have that bonus. I saw some people trying to work with item->GetImmuneFlag() and m_pProto->dwImmuneFlag , but those functions does not return the immune bonuses... those functions returns values from item_proto so you should avoid them. I don't know exactly how this bug exactly works, but I found a solution. After you see it you may think that it's a performance issue, but it's still a fix. Of course, you can make all immunes 100% and in that case FALL will be there too and this is a problem. Of course, you can check and make 100% immune only stun, but that would mean you gived up (at least I feel that xD ). So... let's start. Search in char.h for : IsImmune(DWORD dwImmuneFlag); And add after: void UpdateImmuneFlags(); Now open char_resist.cpp and search for: #include "locale_service.h" And add after : #include "item.h" Now search in the same file for: bool CHARACTER::IsImmune(DWORD dwImmuneFlag) And add on the first line (after { ) : if (!IS_SET(m_pointsInstant.dwImmuneFlag, dwImmuneFlag)) // that means bug may be here UpdateImmuneFlags(); // we update flags And add this BEFORE the function : void CHARACTER::UpdateImmuneFlags() { m_pointsInstant.dwImmuneFlag = 0; // the flag may be reseted because we changed the equipment, but let's be sure for (int i = 0; i < WEAR_MAX_NUM; i++) // we check the entire uquipment... because immune on armor : and maybe other items { if(GetWear(i)) { for (int i2 = 0; i2 < ITEM_APPLY_MAX_NUM; ++i2) // we check the bonuses from proto { if (GetWear(i)->GetProto()->aApplies[i2].bType == APPLY_NONE) continue; else if(GetWear(i)->GetProto()->aApplies[i2].bType == APPLY_IMMUNE_STUN) // we found stun? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN); // we set stun else if(GetWear(i)->GetProto()->aApplies[i2].bType == APPLY_IMMUNE_SLOW) // we found slow? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW); // we set slow else if(GetWear(i)->GetProto()->aApplies[i2].bType == APPLY_IMMUNE_FALL) // finally, we found fall? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL); // we set fall } for (int i3 = 0; i3 < ITEM_ATTRIBUTE_MAX_NUM; ++i3) // we check the bonuses from item { if (GetWear(i)->GetAttributeType(i3)) { const TPlayerItemAttribute& ia = GetWear(i)->GetAttribute(i3); if(ia.bType == APPLY_IMMUNE_STUN) // we found stun? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_STUN); // we set stun else if(ia.bType == APPLY_IMMUNE_SLOW) // we found slow? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_SLOW); // we set slow else if(ia.bType == APPLY_IMMUNE_FALL) // finally, we found fall? SET_BIT(m_pointsInstant.dwImmuneFlag, IMMUNE_FALL); // we set fall } } } } } Now... how actually that works? Everytime you will get attacked the server will automatically check if you have anti-stun. If server will find that you don't have will update the flags using my function and will check again and now will actually "see" if you really have anti-stun. Now some of you will probably think: "Wait... this function only add immune flags... what about deleting them?" The answer is simple: server does that and it does correctly. So don't worry. I tested that and it worked for me. This will be probably the only fix I will post over here. Why? People do not appreciate and usually they say that is copied or is theirs. At least my country does that (Romania) and every guy who just discovered the colors from syntax highlighters is saying that he knows to code. Dat country and dat people. "GG izy" Hope this will help you. If you find something wrong in my code then I am sorry.
    1 point
×
×
  • 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.