Jump to content

Alpha

Bronze
  • Posts

    45
  • Joined

  • Last visited

  • Days Won

    1
  • Feedback

    0%

Alpha last won the day on July 3 2014

Alpha had the most liked content!

2 Followers

About Alpha

Informations

  • Gender
    Female

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Alpha's Achievements

Collaborator

Collaborator (7/16)

  • Dedicated
  • Reacting Well
  • Very Popular Rare
  • Conversation Starter
  • First Post

Recent Badges

461

Reputation

  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
×
×
  • 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.