Jump to content

Alpha

Inactive Member
  • Posts

    45
  • Joined

  • Last visited

  • Days Won

    1
  • Feedback

    0%

Everything posted by Alpha

  1. Mobs should be their own entity you can reduce memory usage by partly by just allocating specific stuff just for players but thats an extra allocation for every entity potentially several more allocations for example if you are using maps and not reserving or resizing you will end up with multiple allocations for a single map
  2. void CAttributeInstance::Render() { for(const auto& vertex : m_v3HeightDataVector) { uint32_t dwColor = 0xff0000ff; Engine::GetDevice().SetTextureFactor(dwColor); Engine::GetDevice().SetFvF(D3DFVF_XYZ); Engine::GetDevice().SetTransform(D3DTS_WORLD, Matrix::Identity); Engine::GetDevice().SetCullMode(D3DCULL_NONE); Engine::GetDevice().DrawPrimitiveUP( D3DPT_TRIANGLELIST, vertex.size() / 3,(void*)vertex.data(), sizeof(Vector3)); } } It's not really a collision it's saved as height in the mdatr file The rendering code i provided is also not the best ... But it works one has just to adjust ist for the old STATEMANAGER interface and call it like if (po->pAttributeInstance) { po->pAttributeInstance->Render(); }
  3. On a side note You actually throw away pythons garbage collector by even having destructors in most cases bool PyTuple_GetWindow(PyObject* poArgs, int pos, UI::CWindow** ppRetWindow) { PyObject* iHandle; if (!PyTuple_GetObject(poArgs, pos, &iHandle)) return false; if (!iHandle) return false; if (!PyCapsule_CheckExact(iHandle)) return false; if (auto* ptr = PyCapsule_GetPointer(iHandle, nullptr); ptr) { *ppRetWindow = static_cast<UI::CWindow*>(ptr); return true; } return false; } // Usage auto win = UI::CWindowManager::Instance().RegisterXYWindow(po, szLayer); auto capsule = PyCapsule_New(win, nullptr, CapsuleDestroyer); return capsule; void CapsuleDestroyer(PyObject* capsule) { auto rawPtr = static_cast<UI::CWindow*>(PyCapsule_GetPointer(capsule, nullptr)); UI::CWindowManager::instance().DestroyWindow(rawPtr); }
  4. Deleting the old grid in the constructor of the new grid just makes destruction less obvious and when working with raw pointers to heap memory you do not want destruction to be hidden. As it can easily lead to heap use after free bugs
  5. But thats already built into the game you can enable it by just adding the ->Deform(); Part for buildings all you are adding seems to be LOD to the animations and that is basically GrannySampleModelAnimationsAcceleratedLOD Some of the M2M Map Objects have Animations builtin and also some metin2 objects there is a watermill for example that has an animation in its gr2 file Ah the rest of your code gets rid of the: "Unable to find matching track_group for Model:" messages
  6. [Hidden Content] You could replace md5 with this and it would probably speed up things
  7. Particle Scaling v2HalfSize.x = v2HalfSize.x * m_scale; v2HalfSize.y = v2HalfSize.y * m_scale;
  8. Nope ... Tim has left the scene a long time ago Also Bela is right. Well you CAN rewrite the ResourceManager and make it more effective. You can also just well do the whole playersettingModule.py in c++ directly and it will dramatically decrease loading times. The calls from python to c++ and back slow it down immensely. (Or use Cython Freeze and cdef functions)
  9. Note that players can fall from their mount now on the official servers and some of the new immune stuff was also implemented for this
  10. cleanmission is called when you send a chat packet from the server with zero lenght so basically ch->ChatPacket(CHAT_TYPE_MISSION, "") Mission messages are not designed to dissapear by time you need to clean them manually
  11. Or you use the official code like this in CPythonNetworkStream::RecvChatPacket(): else if (CHAT_TYPE_MISSION == kChat.type) { if(uChatSize) PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_SetMissionMessage", Py_BuildValue("(s)", buf)); else PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_CleanMissionMessage", Py_BuildValue("()")); } else if (CHAT_TYPE_SUB_MISSION == kChat.type) { PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_SetSubMissionMessage", Py_BuildValue("(s)", buf)); } Instead of the PythonNetworkStreamCommand Part
  12. Just compile the Preprocessor and use it And for texture modification for example RebaseTextureFiles is intended to change the filestrings reported for textures from absolute paths (used by Max and Maya), to paths relative to the root of your game data directory, the character file itself, or any other root you want to specify. preprocessor RebaseTextureFiles file.gr2 -output file_relative.gr2 -basepath c:/game/data/root For modifying textures the granny preprocessor provides Renames granny_file_info members specified by "-rename Name[idx]" preprocessor RenameElement base.gr2 -output base.gr2 -rename textures[0] -newname "d:/ymir work/npc_mount/new_texture_name.dds" Would change texture index 0 to d:/ymir work/npc_mount/new_texture_name.dds You can event automate most of this process just by creating a batch file the processor takes and executes on the given file BonesPerMesh -bonelimit 100 CleanMaterials VertexCacheOptimize PlatformConvert -pointer 32 -endian little Compress With just this and Granny 2.11 you have a good amount of performance gain in metin2 for example This little script for example takes an directory collects all gr2 files and applies a file called dx9.ppb to the collected files from __future__ import print_function import fnmatch import os import subprocess import sys #[Hidden Content] def query_yes_no(question, default="yes"): """Ask a yes/no question via raw_input() and return their answer. "question" is a string that is presented to the user. "default" is the presumed answer if the user just hits <Enter>. It must be "yes" (the default), "no" or None (meaning an answer is required of the user). The "answer" return value is True for "yes" or False for "no". """ valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} if default is None: prompt = " [y/n] " elif default == "yes": prompt = " [Y/n] " elif default == "no": prompt = " [y/N] " else: raise ValueError("invalid default answer: '%s'" % default) while True: sys.stdout.write(question + prompt) choice = raw_input().lower() if default is not None and choice == '': return valid[default] elif choice in valid: return valid[choice] else: sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n") # Print iterations progress #[Hidden Content] def printProgressBar(iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '#'): """ Call in a loop to create terminal progress bar @params: iteration - Required : current iteration (Int) total - Required : total iterations (Int) prefix - Optional : prefix string (Str) suffix - Optional : suffix string (Str) decimals - Optional : positive number of decimals in percent complete (Int) length - Optional : character length of bar (Int) fill - Optional : bar fill character (Str) """ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) bar = fill * filledLength + '-' * (length - filledLength) print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') # Print New Line on Complete if iteration == total: print() print("ATTENTION! This script should only be executed in single folders") print("as it always changes the granny files recursively. We do") print("not want that data bloat in our git repository") print("") accepted = query_yes_no("Are you sure you want to execute the updater?") if not accepted: sys.exit() path = raw_input("Enter the path that you want to convert:") if path == ".": accepted = query_yes_no("Do you know that . is everything?") if not accepted: sys.exit() matches = [] for root, dirnames, filenames in os.walk("source/" + path): for filename in fnmatch.filter(filenames, '*.gr2'): matches.append(os.path.join(root, filename)) total = len(matches) if total <= 0: print("No gr2 file found in path: " + path) sys.exit() printProgressBar(0, total, prefix = 'Progress:', suffix = 'Complete', length = 50) for i, match in enumerate(matches): printProgressBar(i, total, prefix = 'Progress:', suffix = 'Complete', length = 50) subprocess.call(['preprocessor.exe', 'RunBatch', '-batch', 'dx9.ppb', match]) print("Done")
  13. I wrote this function after being asked to Q.Q bool CExchange::CheckSpace() { std::vector<CGrid> s_grids; for (int pCount = 0; pCount < INVENTORY_PAGE_COUNT; ++pCount) { s_grids.push_back(CGrid(5, 9)); s_grids[pCount].Clear(); } LPCHARACTER victim = GetCompany()->GetOwner(); LPITEM item; int i; for (i = 0; i < INVENTORY_MAX_NUM; ++i) { if (!(item = victim->GetInventoryItem(i))) continue; BYTE itemSize = item->GetSize(); BYTE bPage = i / (INVENTORY_PAGE_SIZE) - 1; s_grids[bPage].Put(i - (INVENTORY_PAGE_SIZE * bPage), 1, itemSize); } static std::vector <WORD> s_vDSGrid(DRAGON_SOUL_INVENTORY_MAX_NUM); bool bDSInitialized = false; for (i = 0; i < EXCHANGE_ITEM_MAX_NUM; ++i) { if (!(item = m_apItems[i])) continue; BYTE itemSize = item->GetSize(); if (item->IsDragonSoul()) { if (!victim->DragonSoul_IsQualified()) return false; if (!bDSInitialized) { bDSInitialized = true; victim->CopyDragonSoulItemGrid(s_vDSGrid); } bool bExistEmptySpace = false; WORD wBasePos = DSManager::instance().GetBasePosition(item); if (wBasePos >= DRAGON_SOUL_INVENTORY_MAX_NUM) return false; for (int i = 0; i < DRAGON_SOUL_BOX_SIZE; i++) { WORD wPos = wBasePos + i; if (0 == s_vDSGrid[wBasePos]) { bool bEmpty = true; for (int j = 1; j < item->GetSize(); j++) { if (s_vDSGrid[wPos + j * DRAGON_SOUL_BOX_COLUMN_NUM]) { bEmpty = false; break; } } if (bEmpty) { for (int j = 0; j < item->GetSize(); j++) { s_vDSGrid[wPos + j * DRAGON_SOUL_BOX_COLUMN_NUM] = wPos + 1; } bExistEmptySpace = true; break; } } if (bExistEmptySpace) break; } if (!bExistEmptySpace) return false; } else { bool bFound; for (int pCount = 0; pCount < INVENTORY_PAGE_SIZE; ++pCount) { int iPos = s_grids[pCount].FindBlank(1, itemSize); if (iPos >= 0) { s_grids[pCount].Put(iPos, 1, itemSize); bFound = true; break; } } if (bFound) continue; return false; // No space left in inventory } } return true; } Credits to Martin and Think and all the other Persons who worked on the other fix I used as base. This is untested oh and there is a change in common/length.h INVENTORY_PAGE_SIZE = 45, INVENTORY_PAGE_COUNT = 3, INVENTORY_MAX_NUM = INVENTORY_PAGE_SIZE * INVENTORY_PAGE_COUNT, Basically you can replace INVENTORY_MAX_NUM / 2 with INVENTORY_PAGE_SIZE in all files and if you want to add or remove inventory pages just change INVENTORY_PAGE_COUNT And to repeat it this is as for now untested I actually test it in some minutes. Edit: Basically this is the same as o.o static CGrid s_grid1(5 * INVENTORY_PAGE_COUNT, 9);
  14. Hey guys, I created a tool to generate a exlist.txt by reading a .eix file, I was tired of converting the xml files to a proper file list... So here you have it It should save you some time when unpacking Updates Usage: Just drop the .eix file on it at the moment it just supports single files ExlistCreator.zip
  15. You need to edit the skill_proto and the Affect stuff has to match server and clientside
  16. The source is not included in the metin2 license, and the things you can modify are limited. Ymir regulates what the publishers do. The source is public, there are links where you can download it on the web.
  17. The code is not from me its from rtsummit I think (ymir developer) Novaline is a copy of devline (ongoing development)
  18. [Hidden Content] Read the comments there is a php gauss random function
  19. M2 Download Center Download Here ( Internal ) Hello, I publish the light version of my ProtoReader here, the light version has one functionality. It converts client item_proto and mob_proto the their server version Input: item_proto mob_proto Output: item_names.txt item_proto.txt mob_names.txt mob_proto.txt Its fully automated just double click on it when its in the same folder as the item_proto and mob_proto. It works like dump_proto but in reverse. Attention! Not every value is included in the clientside proto tables it could happen that you have to change some values on your own. ProtoReader is for old item_proto files (before dragon soul (dragon stone alchemy)). ProtoReaderNewFormat is for the current files. Virustotal: [Hidden Content] You find the download in the attachments. When you like my work and this tool, go and visit: I might also do a Pro Version with some other Features like clientside proto to xml or sql or sql to server item_proto and so
  20. Mecury asked three times if you have a matching client binary for the server binarys that he can use and you answered him several times but did not answer that question everytime you answered xD Ah ok, you already answered that several times.
  21. Uhm actually, Magic restance does not work well but, the magic restistance bonus in metin2 works well actually too well, if you have too high magic resistance on your server all shamans and suras are heavily nerved. @Night that would mean that if the hit is critical the defense is doubled too CritDMG = 2NormalDMG - 2ArmorDefense but well thats the easy solution the damage factor would be a lot nicer at the moment anyone in metin2 avoids defense because they think because of the penetrate bonus stuff they get more damage if they have more defense funny thats actually because of the critical hits 100 % critical hit bonus is about 30 percent actually 405 % critical hit bonus is 100 percent
  22. syslog: change the signal timer calls to 120 seconds
  23. o.o You upgraded it? Did you rewrite qc with the new Lexer? I tried to upgrade too the server worked fine but I couldnt upgrade qc because of the Lexer changes in lua 5.1 and 5.2
  24. It's newer than the current source release ... planned for end 2014 I think
  25. The fix I posted in the other thread should work It's my mistake so I should know how to fix it or
×
×
  • 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.