// PORT: adds or replaces whole item_proto records (all 156-byte fields); untouched records stay byte-identical. // Row: vnum type sub size anti flags wear immune buy sell refined refine_set magic_pct // limit0 value0 limit1 value1 apply0 value0 apply1 value1 apply2 value2 v0..v5 specular gain_socket \t name #include "GameLib/StdAfx.h" #include "GameLib/ItemData.h" #include "EterBase/lzo.h" #include #include #include #include #include #include #include #include using Item=CItemData::TItemTable; static constexpr std::array item_key{{173217,72619434,408587239,27973291}}; static std::vector 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(stream),std::istreambuf_iterator()}; } static DWORD word(const std::vector& 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& data,size_t offset,DWORD value){std::memcpy(data.data()+offset,&value,4);} static void dump(const Item& r){ std::printf("%u %u %u %u %u %u %u %u %u %u %u %u %u",r.dwVnum,r.bType,r.bSubType,r.bSize,r.dwAntiFlags,r.dwFlags,r.dwWearFlags,r.dwImmuneFlag, r.dwIBuyItemPrice,r.dwISellItemPrice,r.dwRefinedVnum,r.wRefineSet,r.bAlterToMagicItemPct); for(const auto& limit:r.aLimits)std::printf(" %u %d",limit.bType,int(limit.lValue)); for(const auto& apply:r.aApplies)std::printf(" %u %d",apply.bType,int(apply.lValue)); for(auto value:r.alValues)std::printf(" %d",int(value)); std::printf(" %u %u\t%.*s\n",r.bSpecular,r.bGainSocketPct,int(strnlen(r.szLocaleName,sizeof(r.szLocaleName))),r.szLocaleName); } int main(int argc,char** argv) { const bool dumping=argc==3&&!std::strcmp(argv[1],"--dump"); if(argc!=4&&!dumping){std::fprintf(stderr,"usage: item_proto_patch in_proto rows.tsv out_proto | --dump proto\n");return 2;} if(dumping)argv[1]=argv[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 rows; for(DWORD i=0;i f{}; for(auto& value:f)if(!(stream>>value))throw std::runtime_error("item row: "+line.substr(0,40)); long long extra;if(stream>>extra)throw std::runtime_error("item row has extra columns"); if(name.size()>CItemData::ITEM_NAME_MAX_LEN)throw std::runtime_error("item name too long"); Item r{};int i=0; r.dwVnum=f[i++];r.bType=f[i++];r.bSubType=f[i++];r.bSize=f[i++];r.dwAntiFlags=f[i++];r.dwFlags=f[i++]; r.dwWearFlags=f[i++];r.dwImmuneFlag=f[i++];r.dwIBuyItemPrice=f[i++];r.dwISellItemPrice=f[i++]; r.dwRefinedVnum=f[i++];r.wRefineSet=f[i++];r.bAlterToMagicItemPct=f[i++]; for(auto& limit:r.aLimits){limit.bType=f[i++];limit.lValue=f[i++];} for(auto& apply:r.aApplies){apply.bType=f[i++];apply.lValue=f[i++];} for(auto& value:r.alValues)value=f[i++]; r.bSpecular=f[i++];r.bGainSocketPct=f[i++]; std::memcpy(r.szName,name.data(),name.size());std::memcpy(r.szLocaleName,name.data(),name.size()); (rows.count(r.dwVnum)?replaced:added)++;rows[r.dwVnum]=r; } std::vector plain;for(const auto& pair:rows){const BYTE* bytes=reinterpret_cast(&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 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"); std::ofstream out(argv[3],std::ios::binary|std::ios::trunc); if(!out.write(reinterpret_cast(result.data()),result.size()))throw std::runtime_error("cannot write proto"); std::printf("items added=%zu replaced=%zu total=%zu; verified round-trip\n",added,replaced,rows.size());return 0; }catch(const std::exception& e){std::fprintf(stderr,"%s\n",e.what());return 1;} }