Эта тема уже освещена на жуке, но часть скринов там тупо потерялась, а так же есть не совсем понятные тонкости. Эта тема не претендует на отдельный гайд, она скорее всего дополняет топик на жуке. 1. Всяческими уловками ищем значение. 2. находится от 1 до 100 значений, которые меняются синхронно с значением в игре. 3. Добавляем все, и будем перебирать каждый. Авось, нужный да найдется. 4. Выбираем значение в нижнем списке (обращаем внимание на его адрес. У меня он такой: 0D07C510), щелк по нему Правой кнопкой мыши, и выбираем Find what writes to this adress (Найти что пишет на этот адрес). 5. Немного поизменяем значение в игре, дабы нашлось несколько значений. 6. В списке смотрим только на те, у которых в квадратных скобках есть что-то вроде следующего: 0099E1F2 - 89 87 80020000 - mov [edi+00000280],eax На месте edi может быть что-то другое, но обязательно должны быть квадратный скобки. 7. Выбираем это значение в списке, и тыкаем справа More information (больше информации). 8. Тут нас интерисует 2 цифры: - Это плюсуемое значение, подсвеченное красным. в моем случае это: 0099E1F2 - mov [edi+00000280],eax - И Оффсет. Оффсеты записанны в нижней части, и их там аж 9 штук. Какой же из них выбрать? А очень просто. Т.к. у нас в квадратных скобках именно EDI, то и оффсет смотрим от EDI. У меня это следующее: EDI=0D07C510 9. Закрываем окно с продробной информацией, останавливаем и закрываем поиск того, что ищет что пишет на адрес (Stop - Close). Тыкаем NewScan, указываем тип значение 4 Bytes, и отмечаем галочкой, что значение у нас в хексовом виде (Hex) Вставляем в строку поиска наш оффсет (у меня это 0D07C510) и ищем. 10. Если ничего не нашлось, то нам надо искать по другому игровому значению (мы же на 3 шаге добавили не одно, а несколько). Выбираем следующее значение, и идем начиная с шага 4. Если же нашлось что-то, то идем дальше. 11. В результатах поиска есть 3 колонки: - Adress (Адрес) - Value (значение) - Previous (предыдущее значение) Тыкаем Add Adress Manually (Добавить адрес вручную), отмечаем галочку Pointer (Указатель) и вбиваем туда следующие значения В поле Адрес вбиваем адрес первого найденного только-что значения (из колонки Adress), в поле Оффсет вбиваем первую цифру из 8 шага (у меня это 280). И смотрим на полученный результат сложения. Или у вас это может так-же называться The offset you choose brings it to: Он должен быть равен адресу значения из шага 4 (у меня это 0D07C510). Если он не равен - то вбиваем ручками следующий адрес из результатов поиска, и смотрим на результат сложения/ 12. Оффсеты совпали, и мы добавили указатель в наш список снизу. Далее тык по нему Правой кнопкой мыши и выбираем Find what acess this adress (Найти что получает доступ к этому адресу). Далее тык на первую кнопку Find what acess this pointer. Далее в игре поизменяем любым способом наше игровое значение. Найдется несколько значений. Нам нужно первое, у которого что-то плюсуется в квадратных скобках (как на шаге 6). Тыкаем More information (больше информации) и, как на 8 шаге, записываем или запоминаем те же 2 параметра (см. 8 шаг). У меня получились ESI значения, поэтому я смотрю оффсет ESI (02000368 ) и записываю плюсуемое значение (4). 13. Закрываем окна с подробной информацией и поиском, и начинаем новый поиск оффсета, как на шаге 9. Теперь ищем только-что найденный оффсет (у меня это 02000368 ). 14. В результате что-то находится. Подсвеченный зеленым адрес в первой кнолонке и есть наш базовый адрес. Если не находится, то идем на шаг 11, и добавляем указатель, используя следующий адрес из результатов поиска.
Всем здрасьте. Хочу обсудить кто как пишет чтение-сохранения файлов, дабы в процессе дискуссии выявить самые красивые и быстрые варианты. Привет. Код выглядит читабельным и удобным, как для Windows Forms. Попробуй теперь перейти на WPF и для вывода информации использовать Binding Сам как то мучался с уймой кода, а потом Андрей(pdev) посоветовал биндить и показал как. Сразу я не понял зачем вообще упрощать вывод информации, а потом Данил (daqqq) привел более подробный пример. Теперь ждем топика с примером :-)
Всем здрасьте. Хочу обсудить кто как пишет чтение-сохранения файлов, дабы в процессе дискуссии выявить самые красивые и быстрые варианты. Начну с того, как пишу я. Для примера возмем файл Dynamicobjects.data (Чуть ли не самый простой файл). Структура Естественно-понятно, что прежде чем писать какой-то редактор или парсер файла - мы разбираем его структуру. У динамика структура (для 010) такова: struct object { int ID; int Length; char Path[Length]; }; int sign; int Count; object Object[Count]<optimize=false>; Код Далее я пишу класс, который будет содержать заголовочные переменные, и массивы каких-то блоков (их я объявляю структурой). А что бы код можно было легко и непринужденно переносить в другие проекты (и что бы в этом другом проекте не образовывалась свалка) - сразу переименовываю его в соответсвии с типом файла, с которым работаю Пример класса: using System; using System.Text; using System.IO; namespace DynObj { class DynObj { protected static int Sign = 1347242308; protected static DynObj_CS.Templates.Object[] Objects; } } Тут же в проекте создал папку (Folder), и обозвал её DynObj_CS. Тут будут располагаться все классы для работы с этим файлом. В ней создал папку Templates. Тут будут располагаться все структуры для этого файла. В папке Templates создал класс, и назвал его Object - в него я запишу под структуру Object. Содержимое этого класса: namespace DynObj.DynObj_CS.Templates { struct Object { public int ID; public string Path; } } Чтение в память Далее мы будем читать файл в память. Я делаю это так: В класс для чтения передаю массив байтов, которые закидываю в MemoryStream, к которому подключаю BinaryReader. Получается очень даже симпатичный код. using System; using System.Text; using System.IO; namespace DynObj.DynObj_CS { class Load : DynObj { public static void Start(byte[] fileArr) { MemStream = new MemoryStream(fileArr); file = new BinaryReader(MemStream); int inSign = file.ReadInt32(); if (inSign != Sign) throw new Exception("Неверный тип файла."); readObjects(); file.Close(); MemStream.Close(); } static void readObjects() { int count = file.ReadInt32(); Objects = new Templates.Object[count]; for (int i = 0; i < count; i++) { Objects[i].ID = file.ReadInt32(); Objects[i].Path = readString(); } } static string readString() { int Length = file.ReadInt32(); byte[] strArr = file.ReadBytes(Length); string result = Encoding.GetEncoding(936).GetString(strArr, 0, Length); //Кодировка (Encoding.GetEncoding(936)) захардкоженна а не передана в параметре, тк //в PW почти везде используется именно она //Но для гибкости можно передавать кодировку и в параметре return result; } static MemoryStream MemStream; static BinaryReader file; } } В основном классе подключаем чтение по имени файла и по массиву байт: using System; using System.Text; using System.IO; namespace DynObj { class DynObj { public static void Load(string fileName) { byte[] fileArr = File.ReadAllBytes(fileName); DynObj_CS.Load.Start(fileArr); } public static void Load(byte[] fileArr) { DynObj_CS.Load.Start(fileArr); } protected static int Sign = 1347242308; protected static DynObj_CS.Templates.Object[] Objects; } } Выгрузка из памяти Теперь напишем класс для сохранения всей той информации, что у нас есть. using System; using System.Text; using System.IO; namespace DynObj.DynObj_CS { class Save : DynObj { public static byte[] Start() { MemStream = new MemoryStream(GetFileSize()); file = new BinaryWriter(MemStream); file.Write(Sign); writeObjects(); byte[] result = MemStream.ToArray(); file.Close(); MemStream.Close(); return result; } static void writeObjects() { file.Write(Objects.Length); for (int i = 0; i < Objects.Length; i++) { file.Write(Objects[i].ID); writeString(Objects[i].Path); } } static int GetFileSize() { //Что бы у нас не было много циклов копирования памяти что бы //просто расширить её - мы сразу подсчитаем размер, который нам понадобится //Можно, конечно, задать какой-то фиксированный большой размер //НО для красивого и правильного примера мы так делать не будем int Size = 8;//Header for (int i = 0; i < Objects.Length; i++) { Size += 8;//ID и длинна строки byte[] tmpArr = Encoding.GetEncoding(936).GetBytes(Objects[i].Path); Size += tmpArr.Length; } return Size; } static void writeString(string Value) { byte[] strArr = Encoding.GetEncoding(936).GetBytes(Value); file.Write(strArr.Length); file.Write(strArr); } static MemoryStream MemStream; static BinaryWriter file; } } И подключим в основном классе сохранение: using System; using System.Text; using System.IO; namespace DynObj { class DynObj { public static void Load(string fileName) { byte[] fileArr = File.ReadAllBytes(fileName); DynObj_CS.Load.Start(fileArr); } public static void Load(byte[] fileArr) { DynObj_CS.Load.Start(fileArr); } public static void Save(string fileName) { byte[] fileArr = DynObj_CS.Save.Start(); //Создаем папку для файла - что бы при сохранении не ругался Directory.CreateDirectory(Path.GetDirectoryName(fileName)); File.WriteAllBytes(fileName, fileArr); } public static byte[] Save() { byte[] fileArr = DynObj_CS.Save.Start(); return fileArr; } protected static int Sign = 1347242308; protected static DynObj_CS.Templates.Object[] Objects; } } Итог Вот и всё :) Теперь мы можем загружать и сохранять этот файл. А в промежутке между этими действиями делать с ним всё что угодно :) P.S. Архив с этим проектом. http://files.mail.ru/E0C7DA0DA3AC4C689DB7025389CFB35E
Что есть зависимость, а следующий оратор подвела к ее сути :) И тем самым лишив тебя возможности насладиться открытием в чем именно состоит зависимость.
У вас ошибка скорее всего в названии *ski файлов. Если вы переименовали папку, то и *ski файлы тоже надо переименовывать. Например: Исходное название папки: 夏日清凉装上衣 Файлы в этой папке: 女通用夏日清凉装上衣一级.ski 女通用夏日清凉装上衣三级.ski 女通用夏日清凉装上衣二级.ski 妖精夏日清凉装上衣一级.ski 妖精夏日清凉装上衣三级.ski 妖精夏日清凉装上衣二级.ski Если вы меняете исходное название папки, то у вас получится должно следующее: Новое название папки: Primer Файлы в этой папке: 女通用Primer一级.ski 女通用Primer三级.ski 女通用Primer二级.ski 妖精Primer一级.ski 妖精Primer三级.ski 妖精Primer二级.ski А я что сказал?
А ничего. Посмотри еще как названы .ски модельки в папках разных стилей. Там есть зависимость между именем папки и названием .ски моделек. Вот это, скорей всего, тебя и подвело.
Не путь к папке, а название папки. Посмотри на других стилях. Там есть имя, иконка, моделька для отображения на земле, и название папки со стилем.
Бэкап. Ну или делай анализ логов. Туда, возможно, пишется интересующая тебя информация.
Тысяч за 20 такое сделают Вполне приемлемая цена. Но за эти деньги их заставят буквально всё заставить работать у каждой модельки :-) В моем видении такие вот паки моделек уже со скринами представляли бы куда большую ценность, чем отдельные модельки разбросанные по разным темам на разных форумах.
Так, а теперь вот вам соревнование: Пофиксить все модельки Jade Dynasty, встречающиеся в models.pck, поскринить их, и выложить. Да, у каждой модельки должны быть все эффекты и другие ресурсы, на которые ссылается .есм моделька, но не более. Каждую отдельную модельку закинуть в каждую отдельную папку.
Измени структуру .pck архива, все .ехе файлы и их .ДЛЛки закинь в молебокс (купленный). Откажись от CPW - используй только ручные обновы.
Даже после конверта геодаты шахты будут себя так-же вести :-) Тут надо геодату поднимать до уровня пола.
- Админ форума не может быть в WL.
Большой риск, если только не воспользуетесь его железом и каналом не по прямому назначению.
Спасибо,буду разбираться. Там сильно большая разница? И карты придут в работоспособное состояние,когда исправить эти 2 файла и все? Нет, не всё :-) Но если ты поднимешься на эту ступеньку, то остальные будешь делать на автомате :-)
Сам ду10 засветился,может поделитесь способом фикса карт 14 и 15 версии? :) Ну или хотябы натолкните в нужное русло Разбери структуру .ecwld, и .ecbsd. Затем пойми чем различаются разные версии, и убирай эту разницу.
Фишка говоришь? У меня таких фишек более 80 штук уже готово...перегнать пару лок из другой игры,МММ,все,лучший сервер Перегнать, а потом еще придумать интересное наполнение, расставить мобов, понаписать квестов, всяких плюшек понадобавлять, и тд, и тп.
Простая программа для сбора всех нужных файлов для .ecm файла, или списка .ecm файлов. Resourses directory: каталог, который содежрит 4 под-каталога(gfx, models, sfx, grasses). Например: C:\PWRD\PW2\element. *.pck.files - Указывает на то, что, gfx, models, sfx, и grasses каталоги являются под каталогами папок (gfx.pck.files\gfx, models.pck.files\models, sfx.pck.files\sfx, grasses.pck.files\grasses). Output directory: Куда всё будет складываться. Например: C:\new\test. *.pck.files - указывает на то, что gfx, models, sfx, и grasses будут собранны в под-каталоги (gfx.pck.files\gfx, models.pck.files\models, sfx.pck.files\sfx, grasses.pck.files\grasses). Single .ecm file: указывает на то, что выбран один .ecm файл. List of .ecm files: указывает на то, что используется список .ecm файлов. From file: указывает на то, что список находится в файле. Примечание: список должен быть в Юникоде (UTF-16).From list: указывает на то, что список берется из программы. ECP: for Perfect World: указывает на то, что .ecp файлы (отвечающие за "каркас" (непроходимость) моделек), будут сложенны в grasses\ecmodelhull а не в models\ecmodelhull. Скачать: http://dump.ru/file/5339474 [img] Change log: v 1.1: - Исправленны мелкие баги; - Добавленн перенос .att файлов. v 1.2: - Исправленны мелкие баги; - Добавленна поддержка списка файлов в программе; - Добавленн перенос .ecp файлов.
2 параметра сменил, и называш это новым полетом. Куда катится этот мир?
Китайцы делают множество игрушек на движке пв. Пангу использовали модельки только из половины этих игр, а ведь на протяжении всего этого времени, хотя бы раз в месяц, выходили обновления каждой из игрушек. Вот тебе и куча контента, которого ещё ни у кого нет. Подключаеш фантазию, все свои умения, и делаеш за пару недель что-то покруче того же Пангу.
Имена участников (разделяйте запятой).