61 lines
3.8 KiB
C++
61 lines
3.8 KiB
C++
// PORT: isolated item-table extension. All non-biology records stay byte-identical.
|
|
#include "GameLib/StdAfx.h"
|
|
#include "GameLib/ItemData.h"
|
|
#include "EterBase/lzo.h"
|
|
#include <array>
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
#include <cstdio>
|
|
using Item=CItemData::TItemTable;
|
|
static constexpr std::array<DWORD,4> item_key{{173217,72619434,408587239,27973291}};
|
|
static std::vector<BYTE> read_file(const char* path){
|
|
std::ifstream stream(path,std::ios::binary);
|
|
if(!stream)throw std::runtime_error("cannot read proto");
|
|
return {std::istreambuf_iterator<char>(stream),std::istreambuf_iterator<char>()};
|
|
}
|
|
static DWORD word(const std::vector<BYTE>& data,size_t offset){
|
|
if(offset+4>data.size())throw std::runtime_error("truncated proto");
|
|
DWORD value;std::memcpy(&value,data.data()+offset,4);return value;
|
|
}
|
|
static void put_word(std::vector<BYTE>& data,size_t offset,DWORD value){std::memcpy(data.data()+offset,&value,4);}
|
|
static void write_file(const char* path,const std::vector<BYTE>& data){
|
|
std::ofstream stream(path,std::ios::binary|std::ios::trunc);
|
|
if(!stream.write(reinterpret_cast<const char*>(data.data()),data.size()))throw std::runtime_error("cannot write proto");
|
|
}
|
|
int main(int argc,char** argv) {
|
|
if(argc!=4)return 2;
|
|
try {
|
|
static CLZO lzo; auto key=item_key;
|
|
auto input=read_file(argv[1]);
|
|
if(input.size()<20 || std::memcmp(input.data(),"MIPX",4) || word(input,4)!=1 || word(input,8)!=sizeof(Item))throw std::runtime_error("item proto stride");
|
|
CLZObject decoded;
|
|
if(!CLZO::Instance().Decompress(decoded,input.data()+20,key.data()))throw std::runtime_error("item proto decode");
|
|
if(decoded.GetSize()!=size_t(word(input,12))*sizeof(Item))throw std::runtime_error("proto count/size mismatch");
|
|
std::map<DWORD,Item> rows;
|
|
for(DWORD i=0;i<word(input,12);++i){Item r;std::memcpy(&r,decoded.GetBuffer()+i*sizeof(Item),sizeof(Item));rows[r.dwVnum]=r;}
|
|
std::ifstream file(argv[2],std::ios::binary);std::string line;size_t changed=0;
|
|
while(std::getline(file,line)) {
|
|
std::istringstream stream(line); unsigned v,type,sub,size,anti,flags,buy,sell;
|
|
if(!(stream>>v>>type>>sub>>size>>anti>>flags>>buy>>sell))throw std::runtime_error("biology item row");
|
|
std::array<int,6> values{};for(auto& value:values)if(!(stream>>value))throw std::runtime_error("biology item values");
|
|
std::string name;std::getline(stream,name);if(!name.empty()&&name[0]=='\t')name.erase(0,1);
|
|
if(name.size()>24)throw std::runtime_error("biology item name too long");
|
|
Item r{};r.dwVnum=v;r.bType=type;r.bSubType=sub;r.bSize=size;r.dwAntiFlags=anti;r.dwFlags=flags;
|
|
r.dwIBuyItemPrice=buy;r.dwISellItemPrice=sell;
|
|
for(int i=0;i<6;++i)r.alValues[i]=values[i];
|
|
std::memcpy(r.szName,name.data(),name.size());std::memcpy(r.szLocaleName,name.data(),name.size());
|
|
rows[v]=r;++changed;
|
|
}
|
|
std::vector<BYTE> plain;for(const auto& pair:rows){const BYTE* bytes=reinterpret_cast<const BYTE*>(&pair.second);plain.insert(plain.end(),bytes,bytes+sizeof(Item));}
|
|
CLZObject encoded;if(!CLZO::Instance().CompressEncryptedMemory(encoded,plain.data(),plain.size(),key.data()))throw std::runtime_error("encode");
|
|
std::vector<BYTE> result(input.begin(),input.begin()+20);put_word(result,12,rows.size());put_word(result,16,encoded.GetSize());
|
|
result.insert(result.end(),encoded.GetBuffer(),encoded.GetBuffer()+encoded.GetSize());
|
|
CLZObject verified;if(!CLZO::Instance().Decompress(verified,result.data()+20,key.data()) || verified.GetSize()!=plain.size() || std::memcmp(verified.GetBuffer(),plain.data(),plain.size()))throw std::runtime_error("round-trip");
|
|
write_file(argv[3],result);std::printf("biology items=%zu total=%zu; verified round-trip\n",changed,rows.size());return 0;
|
|
}catch(const std::exception& e){std::fprintf(stderr,"%s\n",e.what());return 1;}
|
|
}
|