В общем, как я писал ранее, я сел за написание утилиты для редактирования файлов клиента Lineage 2.
Итак, уже есть чем поделиться(правда конвертирование пока только в одну сторону).
На данный момент реализованы 2 ключевых класса для чтения.
L2FileInputStream
Как можно догадаться по названию, этот класс предоставляет возможность читать данные из файлов клиента. Он служит заменой утилите l2encdec, на лету снимает крипт и распаковывает.
L2DataInputStream
Этот класс реализует интерфейс DataInput, предоставляя методы для чтения базовых классов. Также он умеет считывать объекты по классу через рефлекшн.
Структура файлов описывается классами
Поэтому мы сразу получаем богатый набор инструментов для работы с ними(ORM, OXM, итд).
Пример использования(Клиент Lindvior NA)
Результат:Итак, уже есть чем поделиться(правда конвертирование пока только в одну сторону).
На данный момент реализованы 2 ключевых класса для чтения.
L2FileInputStream
Как можно догадаться по названию, этот класс предоставляет возможность читать данные из файлов клиента. Он служит заменой утилите l2encdec, на лету снимает крипт и распаковывает.
L2DataInputStream
Этот класс реализует интерфейс DataInput, предоставляя методы для чтения базовых классов. Также он умеет считывать объекты по классу через рефлекшн.
Структура файлов описывается классами
Поэтому мы сразу получаем богатый набор инструментов для работы с ними(ORM, OXM, итд).
Пример использования(Клиент Lindvior NA)
PHP код:
<?php
import ee.l2.clientstuff.files.*;
import ee.l2.clientstuff.files.dat.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.FileInputStream;
public class Test2 {
@XmlRootElement
@DatFile(value = "ActionName", localizable = true)
@SafePackage
public static class ActionNameDat{
public ActionName[] actionName;
}
public static class ActionName{
@IntConst(1)
public int tag;
public int id;
public int type;
public int category;
@Length(lengthType = LengthType.COMPACT)
public int[] unkIds;
public String name;
public String icon;
public String icon2;
public String desc;
public boolean unkBool;
@Unicode
public String cmd;
}
public static void main(String[] args) throws Exception{
Class<ActionNameDat> datClass = ActionNameDat.class;
String datName = DatNameUtil.getFileName(datClass);
ActionNameDat dat = new L2DatInputStream(
new L2FileInputStream(
new FileInputStream("D:\\Lineage II\\System\\"+ datName),
datName
)
).readObject(datClass);
JAXBContext context = JAXBContext.newInstance(ActionNameDat.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", true);
marshaller.marshal(dat, System.out);
}
}
[SRC="xml"]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<actionNameDat>
<actionName>
<tag>1</tag>
<id>5000</id>
<type>-1</type>
<category>5</category>
<unkIds>1538</unkIds>
<name>Hand of Warmth</name>
<icon>BranchSys.icon.br_rudolf_hand_i00</icon>
<icon2>none</icon2>
<desc>Can express affection to Rudolph. Affection Level rises by 25%. Warning: Can be used only when a Rudolph requests expression of affection, and cannot be used while transformed!</desc>
<unkBool>false</unkBool>
<cmd>usepetskill</cmd>
</actionName>
...
</actionNameDat>
[/SRC]
Как видите, всего лишь описав формат дат-файла в виде класса, мы получили возможность его экспорта в xml. По-моему это круто
Можно как в l2jc1 генерировать датапак на основе файлов клиента.
Числа и строки
Типы из DDF:
CNTR - INT, записанный в компактном виде. В классах описывается как переменная с типом int или Integer, с добавлением аннотации @Compact.
ASCF/UNICODE - Строки, в классах описываются типом String. Если это UNICODE, то добавляется аннотация @Unicode.
Для проверки данных определены 2 аннотации IntConst/StrConst. Если определенные значения не совпадают со считанными, то выбрасывается исключение(мб и найдется применение).
Массивы
Поддерживаются только одномерные массивы.
Длина массива по умолчанию считывается как int. Если длина массива константа, и ее не нужно считывать, то добавляется аннотация @Length(<значение>). Если длина массива определяется CNTR, то добавляется аннотация @Length(lengthType = LengthType.COMPACT).
Планы на ближайшее будущее:
- Замена xml более читабельным форматом
- Описать датки
- Автоматическая компиляция классов даток из более примитивных исходников DONE
- Запись обратно в файл DONE
- unreal packages
Проект на гитхабе/src
Жду ваших замечаний/пожеланий.
Если хотите поучаствовать - пишите.