Nghĩ lại ngày xưa, nhiều người hợp tác, đầu tư làm server ts, lên con số vài tỉ, nhưng cuộc sống bản thân tôi còn không ổn, làm sao theo nổi những dự án tầm cỡ vĩ đại như trên. Bây giờ bình tâm lại, giữ lại kiến thức cũng không giúp được gì, vì thời gian không cho phép ngồi code và quản trị cái hệ thống đó, nên giờ chia sẽ kiến thức với mọi người. Vì vậy, nên hôm nay tôi mở chuyên mục tư vấn về hệ thống TSOnline, mọi người có thể đặt bất cứ câu hỏi gì về server TS, ví dụ muốn làm server cần điều kiện gì, giải mã data thế nào, các dự án TS hiện giờ thế nào... Còn về các bí mật sâu hơn về hệ thống, như hệ thống warp, talk, Quest... vận hành thế nào, tôi sẽ trả lời về nó, chỉ cần bạn chứng minh 1 điều, và cam kết 1 điều. - Điều phải chứng minh: Cho tôi thấy được bạn đã giải quyết packet Nhật ký Quest. - Điều phải cam kết: Mở 1 server TS phi lợi nhuận để mọi người cùng tham gia, chi phí tính vào chi phí donate. Còn bạn muốn mở server ts để kiếm tiền thì xin lỗi, tôi không giúp bạn được. Talk.Dat PHP: { FileName = "Talk.Dat"; iBlock = 257; var buffer = getBuffer(); //Kiểm tra đường dẫn và đọc hết toàn bộ byte từ file (ReadAllBytes) if (buffer != null) { var sheet = CreateSheet(p, "Talk"); int iTotalBlock = buffer.Length / iBlock; listData = new List<TsOnline.Entity.TalkEntity>(); sheet.Cells[1, 1].Value = "TalkID"; sheet.Cells[1, 2].Value = "Content"; for (int i = 1; i < iTotalBlock; i++) { TsOnline.Entity.TalkEntity item = new TsOnline.Entity.TalkEntity(); int index = i * iBlock; sheet.Cells[i + 1, 1].Value = item.TalkID = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; item.LengthContent = buffer[index++]; Array.Reverse(buffer, index, 254); sheet.Cells[i + 1, 2].Value = item.Content = Encoding.Default.GetString(buffer, index, item.LengthContent).Trim(); listData.Add(item); raiseSendMessage(string.Format("Talk.Dat: {0}/{1}", i, iTotalBlock - 1)); raiseProgress(i * 100 / iTotalBlock); } } } private ushort ProgressUshort(ushort input) { return (ushort)((input ^ 0xECEA) - 5); } Warp.Dat PHP: { FileName = "Warp.Dat"; iBlock = 23; var buffer = getBuffer(); if (buffer != null) { var sheet = CreateSheet(p, "Warp"); int iTotalBlock = buffer.Length / iBlock; listData = new List<TsOnline.Entity.WarpEntity>(); sheet.Cells[1, 1].Value = "Name"; sheet.Cells[1, 2].Value = "b1"; sheet.Cells[1, 3].Value = "b2"; sheet.Cells[1, 4].Value = "u1"; sheet.Cells[1, 5].Value = "i1"; sheet.Cells[1, 6].Value = "i2"; for (int i = 1; i < iTotalBlock; i++) { TsOnline.Entity.WarpEntity item = new TsOnline.Entity.WarpEntity(); int index = i * iBlock; item.LengthName = buffer[index++]; Array.Reverse(buffer, index, 10); sheet.Cells[i + 1, 1].Value = item.Name = Encoding.Default.GetString(buffer, index, item.LengthName).Trim(); index += 10; sheet.Cells[i + 1, 2].Value = item.b1 = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 3].Value = item.b2 = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 4].Value = item.u1 = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 5].Value = item.i1 = ProgressInt(BitConverter.ToInt32(buffer, index)); index += 4; sheet.Cells[i + 1, 6].Value = item.i2 = ProgressInt(BitConverter.ToInt32(buffer, index)); index += 4; listData.Add(item); raiseSendMessage(string.Format("Warp.Dat: {0}/{1}", i, iTotalBlock - 1)); raiseProgress(i * 100 / iTotalBlock); } } } private byte ProgressByte(byte input) { return (byte)((input ^ 0xC8) - 1); } private ushort ProgressUshort(ushort input) { return (ushort)((input ^ 0x5209) - 1); } private int ProgressInt(int input) { return (int)((input ^ 0x0BAEB716) - 1); } Skill.Dat PHP: public enum EnumSkillCategory : byte { ĐánhThường = 0, Địa = 1, Thủy = 2, Hỏa = 3, Phong = 4, Tâm = 5, LướiBắt = 6, TiễnLâu = 7, PhòngNgự = 8, ChạyTrốn = 9, VậtPhẩm = 10, HấpHuyết = 11, PhúcThầnAiThần = 12, GiảiHộChủ = 13, BùaChú = 14, CựĐạiQuái = 15, ĐặcKỹVõTướng = 16, } public enum EnumElement:byte { Không=0, Địa=1, Thủy=2, Hỏa=3, Phong=4, Tâm=5, TuỳNhânVậtSửDụng=6 }public enum EnumSkillStatus:byte { BìnhThường=0, PhongẤnBăngPhong=1, PhongẤnToànPhong=2, PhongẤnThụTinh=3, PhongẤn=4, PhongẤnVựngKích=5, PhongẤnHônThụy=6, PhongẤnChấpThiếp=7, PhongẤn1, PhongẤn2, PhongẤn3, PhongẤn4, PhongẤn5, PhongẤn6, PhongẤn7, PhongẤn8, PhongẤn9, PhongẤn10, PhongẤn11, PhongẤn12, PhongẤn13, PhongẤn14, PhongẤn15, PhongẤn16, PhongẤn17, PhongẤn18, PhongẤn19, PhongẤn20, PhongẤn21, PhongẤn22, PhongẤn23, PhongẤn24, PhongẤn25, PhongẤn26, PhongẤn27, PhongẤn28, PhongẤn29, PhongẤn30, PhongẤn31, PhongẤn32, PhongẤn33, PhongẤn34, PhongẤn35, PhongẤn36, PhongẤn37, PhongẤn38, PhongẤn39, PhongẤn40, PhongẤn41, PhongẤn42, PhongẤn43=50, CườngHóaPhongChiChiếnÝ=51, CườngHóaCuồngNhiệtChiếnHồn=52, CườngHóaMinhKínhChiThủy=53, CườngHóa1, CườngHóa2, CườngHóa3, CườngHóa4, CườngHóa5, CườngHóa6, CườngHóa7, CườngHóa8, CườngHóa9, CườngHóa10, CườngHóa11, CườngHóa12, CườngHóa13, CườngHóa14, CườngHóa15, CườngHóa16, CườngHóa17, CườngHóa18, CườngHóa19, CườngHóa20, CườngHóa21, CườngHóa22, CườngHóa23, CườngHóa24, CườngHóa25, CườngHóa26, CườngHóa27, CườngHóa28, CườngHóa29, CườngHóa30, CườngHóa31, CườngHóa32, CườngHóa33, CườngHóa34, CườngHóa35, CườngHóa36, CườngHóa37, CườngHóa38, CườngHóa39, CườngHóa40, CườngHóa41, CườngHóa42, CườngHóa43, CườngHóa44, CườngHóa45, CườngHóa46, CườngHóa47, BiếnHóaKếtGiới=101, BiếnHóaLẫnTránh=102, BiếnHóaKính=103, BiếnHóaTườngBăng=104, BiếnHóaẨnThân=105, BiếnHóaNguyênKhí=106, BiếnHóaPhóngĐại=107, BiếnHóaĐồngTâm=108, BiếnHóaCổVũ=109, BiếnHóaLinhKính=110, BiếnHóaĐơnDươngHộThể=111, BiếnHóaĐẩuChuyểnTinhDi=112, BiếnHóaVôHìnhVôTướng=113, BiếnHóa1, BiếnHóa2, BiếnHóa3, BiếnHóa4, BiếnHóa5, BiếnHóa6, BiếnHóa7, BiếnHóa8, BiếnHóa9, BiếnHóa10, BiếnHóa11, BiếnHóa12, BiếnHóa13, BiếnHóa14, BiếnHóa15, BiếnHóa16, BiếnHóa17, BiếnHóa18, BiếnHóa19, BiếnHóa20, BiếnHóa21, BiếnHóa22, BiếnHóa23, BiếnHóa24, BiếnHóa25, BiếnHóa26, BiếnHóa27, BiếnHóa28, BiếnHóa29, BiếnHóa30, BiếnHóa31, BiếnHóa32, BiếnHóa33, BiếnHóa34, BiếnHóa35, BiếnHóa36, BiếnHóa37, BiếnHóa38, BiếnHóa39, BiếnHóa40, BiếnHóa41, BiếnHóa42, BiếnHóa43, BiếnHóa44, BiếnHóa45, BiếnHóa46, BiếnHóa47, BiếnHóa48, BiếnHóa49, BiếnHóa50, BiếnHóa51, BiếnHóa52, BiếnHóa53, BiếnHóa54, BiếnHóa55, BiếnHóa56, PhúcThần=170, SuyNhượcTrúngĐộc=171, SuyNhượcThuNhỏ=172, SuyNhượcHỗnLoạn=173, SuyNhượcOaLýPhản174, SuyNhượcChậm=175, SuyNhượcMiss=176, SuyNhượcThổBăng=177, SuyNhượcMãnhĐộc=178, SuyNhượcChúcDung=179, SuyNhượcThứcQuỷHấpHồn=180, SuyNhượcHắcĐồNhamVươngSát=181, SuyNhược1, SuyNhược2, SuyNhược3, SuyNhược4, SuyNhược5, SuyNhược6, SuyNhược7, SuyNhược8, SuyNhược9, SuyNhược10, SuyNhược11, SuyNhược12, SuyNhược13, SuyNhược14, SuyNhược15, SuyNhược16, SuyNhược17, SuyNhược18, SuyNhược19, SuyNhược20, SuyNhược21, SuyNhược22, SuyNhược23, SuyNhược24, SuyNhược25, SuyNhược26, SuyNhược27, SuyNhược28, SuyNhược29, SuyNhược30, SuyNhược31, SuyNhược32, SuyNhược33, SuyNhược34, SuyNhược35, SuyNhược36, SuyNhược37, SuyNhược38, SuyNhược39, SuyNhược40, SuyNhược41, SuyNhược42, SuyNhược43, SuyNhược44, SuyNhược45, SuyNhược46, SuyNhược47, SuyNhược48, SuyNhược49, SuyNhược50, SuyNhược51, SuyNhược52, SuyNhược53, SuyNhược54, SuyNhược55, SuyNhược56, SuyNhược57, SuyNhược58, AiThần=240, HộChủ=241, Max=245 } public enum EnumSkillTypeStatus:byte { BìnhThường = 0, KỹNăngHợpKích = 1, KỹNăngPhiHợpKích = 2, PhongẤn = 3, BiếnHóa = 4, HồiPhục_LoạiTrừBạn = 5, HồiMaLực = 6, TrịLiệu = 7, PhụcHoạt = 8, PhânThân = 9, PhòngNgự = 10, BắtGiữ = 11, ChạyTrốn = 12, SửDụngVậtPhẩm = 13, SongBổ = 14, SuyNhược = 15, LoạiTrừKẻThù = 16, ĐặcThù = 17, TrịLiệuHồiPhục = 18, CườngHóa = 19, }{ FileName = "Skill.Dat"; iBlock = 86; var buffer = getBuffer(); if (buffer != null) { var sheet = CreateSheet(p, "Skill"); int iTotalBlock = buffer.Length / iBlock; listData = new List<TsOnline.Entity.SkillEntity>(); sheet.Cells[1, 1].Value = "SkillName"; sheet.Cells[1, 2].Value = "iCategorySkill"; sheet.Cells[1, 3].Value = "SkillID"; sheet.Cells[1, 4].Value = "SP"; sheet.Cells[1, 5].Value = "iElement"; sheet.Cells[1, 6].Value = "NumberElement"; sheet.Cells[1, 7].Value = "ValueElement"; sheet.Cells[1, 8].Value = "Level"; sheet.Cells[1, 9].Value = "iCachDanh"; sheet.Cells[1, 10].Value = "PhamViTanCong"; sheet.Cells[1, 11].Value = "SoLuotDanh"; sheet.Cells[1, 12].Value = "SoGiay"; sheet.Cells[1, 13].Value = "iStatusSkill"; sheet.Cells[1, 14].Value = "SoLanCongKich"; sheet.Cells[1, 15].Value = "LevelRestriction"; sheet.Cells[1, 16].Value = "PointLearnSkill"; sheet.Cells[1, 17].Value = "PointUpdateSkill"; sheet.Cells[1, 18].Value = "MaxSkillLevel"; sheet.Cells[1, 19].Value = "SkillIdRequired"; sheet.Cells[1, 20].Value = "iLoaiHinhCongKich_"; sheet.Cells[1, 21].Value = "iPhanBietKyNang"; sheet.Cells[1, 22].Value = "SkillIdCanLearn"; sheet.Cells[1, 23].Value = "uEquip3"; sheet.Cells[1, 24].Value = "uEquip4"; sheet.Cells[1, 25].Value = "uEquip5"; sheet.Cells[1, 26].Value = "Description"; for (int i = 1; i < iTotalBlock; i++) { TsOnline.Entity.SkillEntity item = new TsOnline.Entity.SkillEntity(); int index = i * iBlock; item.LengthSkillName = buffer[index++]; Array.Reverse(buffer, index, 20); sheet.Cells[i + 1, 1].Value = item.SkillName = Encoding.Default.GetString(buffer, index, item.LengthSkillName).Trim(); index += 20; sheet.Cells[i + 1, 2].Value = item.iSkillCategory = (EnumSkillCategory)ProgressByte(buffer[index++]); sheet.Cells[i + 1, 3].Value = item.SkillID= ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 4].Value = item.SP = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 5].Value = item.iElement = (EnumElement)ProgressByte(buffer[index++]); sheet.Cells[i + 1, 6].Value = item.NumberElement = ProgressInt(BitConverter.ToInt32(buffer, index)); index += 4; sheet.Cells[i + 1, 7].Value = item.ValueElement = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 8].Value = item.Level = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 9].Value = item.iCachDanh = (EnumSkillTypeStatus)ProgressByte(buffer[index++]); sheet.Cells[i + 1,10].Value = item.PhamViTanCong = (EnumCategoryRangeAttack)ProgressByte(buffer[index++]); sheet.Cells[i + 1, 11].Value = item.SoLuotDanh = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 12].Value = item.SoGiay = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 13].Value = item.iStatusSkill = (EnumSkillStatus)ProgressByte(buffer[index++]); sheet.Cells[i + 1, 14].Value = item.SoLanCongKich = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 15].Value = item.LevelRestriction = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 16].Value = item.PointLearnSkill = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 17].Value = item.PointUpdateSkill = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 18].Value = item.MaxSkillLevel = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 19].Value = item.SkillIdRequired = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 20].Value = item.iLoaiHinhCongKich_ = (EnumTypeAttack)ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 21].Value = item.iPhanBietKyNang = (EnumPhanBietSkill)ProgressByte(buffer[index++]); sheet.Cells[i + 1, 22].Value = item.SkillIdCanLearn = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 23].Value = item.uEquip3 = ProgressByte(buffer[index++]); sheet.Cells[i + 1, 24].Value = item.uEquip4 = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; sheet.Cells[i + 1, 25].Value = item.uEquip5 = ProgressUshort(BitConverter.ToUInt16(buffer, index)); index += 2; item.LengthDescription = buffer[index++]; Array.Reverse(buffer, index, 30); sheet.Cells[i + 1, 26].Value = item.Description = Encoding.Default.GetString(buffer, index, item.LengthDescription).Trim(); listData.Add(item); raiseSendMessage(string.Format("Skill.Dat: {0}/{1}", i, iTotalBlock - 1)); raiseProgress(i * 100 / iTotalBlock); } } } private byte ProgressByte(byte input) { return (byte)(((input ^ 0xFD) & 0xFF) - 4); } private ushort ProgressUshort(ushort input) { return (ushort)((input ^ 0x6EA0) - 4); } private int ProgressInt(int input) { return (int)((input ^ 0xBDEDEBF) - 4); } 24/9/2013: Có bạn hỏi tôi, muốn làm server game cần những gì, đây tôi nêu 1 số kiến thức trong khả năng có hạn của tôi. 1. Kiến thức lập trình căn bản, và ngôn ngữ lập trình chỉ cần hỗ trợ lập trình socket. 2. Có chút kiến thức về packet. Vì việc đầu tiên không phải là phân tích packet đó làm gì, muh là packet đó có cấu trúc như thế nào. 3. Có chút kinh nghiệm về mã hóa. Như chụp packet khi đăng nhập, xem nó packet có giống nhau sau 2 lần chụp hay không... 4. Có chút kinh nghiệm về research. Thời buổi này bác Gu Gồ bự lắm, kiếm gì cũng có, quan trọng là phải biết kiếm đúng chỗ. 5. Kiếm chút tài liệu về asm để đọc, có thể đọc để debug ở mức căn bản, còn không làm được, thì ráng kiếm làm sao có Data của của game do các cao thủ nào leak ra, rồi sử dụng nó làm data căn bản. 6. Biết điểm dừng lại. Vì 1 người không thể làm hoàn chỉnh 1 server được đâu, nếu muôn học hỏi thì nên đưa target tầm ngắn thôi. Và đơn giản nhất là làm mấy cái BOT trước, vì BOT nó đơn giản hơn server game nhiều. 7. Nắm vững cấu trúc dữ liệu, vì "int A = 4;" khác với "byte A = 4". ..... Còn nhiều, rất nhiều cái để nói, vài dòng trên đây không thể nói hết. Nếu anh em muốn gặp nhau chia sẽ kinh nghiệm ở TPHCM thì lúc nào cũng hoan nghênh. Vì kiến thức không thể phát triển nếu không chia sẽ.
Về cá nhân tôi, về tình hình các dự án Private hiện giờ, dù làm thêm 1-2 năm nữa cũng không thể gọi là hoàn thiện. Không phải code xong các packet là xong, còn nhiều yếu tố khác, chính vì vậy đa số các dự án private đều bị ngưng lại không thể hoàn thiện. Tôi sẵn sàng cung cấp thông tin để hoàn thiện Private với điền kiện thỏa mãn 2 yêu cầu ở trên. Nhiều người cứ nghĩ code xong packet, xong thu thập thông tin rồi add vào db là có thể xong. 1 NPC tùy theo điều kiện có thể nói chuyện, active Q, kết thúc Q, hay gia nhập đội ngũ...Nhiều vấn đề, không thể cứ thu thập là xong.
ok, vậy tức là mở sv theo dạng F2P và có cash shop giống như các game hiện nay vấn đề còn lại, hiện giờ chỉ có duy nhất 1 người cầm source Ts ( ít nhất là ở GVN này ), nên cũng chưa biết là tình hình sẽ đi đến đâu =)
Rất nhiều người vs 1 hoài bão chung là 1 SV Ts Final cho AE chơi nhưng mà khó khăn là vô vàn nên chắc ....
Hình như các bạn bị nhầm lẫn 1 số cái. Phi lợi nhuận nghĩa là mở TS để mọi người tham gia, còn donate là tùy vào cộng đồng chung tay chung tay phát triển. Donate nghĩa là không bắt buộc phải trả phí để tham gia tính năng game. Còn về việc chia sẽ hay không, thì như tôi đã nói, tôi sẵn sàng trả lời các bạn về mặt hệ thống TS, từ cấu trúc data, tới packet game. Nhưng tại sao phải có 2 điều kiện đó mới share hết, vì 1 cái là điều kiện cần là để tôi tin rằng bạn có khả năng phát triển code server, và 1 cái tôi tin rằng bạn làm vì đam mê chứ không phải tiền. Ai cũng muốn làm server final, thật ra với source của DVT hiện giờ, chỉ cần tái cấu trúc lại thì có thể thành final luôn rồi, thời gian hoàn thành cỡ 3 tháng (điều này tùy vào 2 yếu tố). Còn bây giờ tôi share hết tất cả, thậm chí source code, thì sẽ thế nào ? ai sẽ là người phát triển, vận hành ? Và ai dám đảm bảo người phát triển đó duy trì game theo hướng cộng đồng ? hay duy trì game theo hướng "hút máu" ? Tôi cũng đính chính lại, mục đích tôi mở Topic này, là để giải đáp 1 số câu hỏi liên quan tới server game, cho những ai hiểu biết về lập trình có thể làm được, chứ không phải tôi mở server game, cũng không phải tôi kinh doanh game, cũng không phải tôi tìm đối tác kinh doanh game.
Thực ra mà nói, bh làm sever mà ko có kinh phí thì khó duy trì lắm, bảo làm free để mọi người chơi thì chắc chả ai chịu đứng ra làm cả, mình nghĩ là nên để thu phí nhưng ở mức thấp và ko có cash shop, chỉ để dùng duy trì sever chứ ko phải là dùng vào việc kinh doanh có lợi nhuận, đây chỉ là ý kiến riêng e thôi, mong các bác ném gạch nhẹ thôi :(
Tôi xin nói lại lần nữa, ở đây tôi không bàn về định hướng kinh doanh, kế hoạch phát triển, mà tôi sẵn sàng share hết cho người nào làm vì đam mê, chứ không phải làm vì tiền. Cái phuơng án tôi đưa ra là một hình thức như các Open source nước ngoài thôi.
thế bác có thể up source cho mọi người củg phát triển theo ý minh dc hok? nếu ai cũg có 1 source thì sẽ hok có chuyện mở sever đôc quyền để kím tiền cả.
Có cần làm luôn hướng dẫn chi tiết cách sửa source, vị trí nào, code nào làm gì luôn không ? Toàn bộ source code của tôi hơn 70k dòng code, và hiện giờ tôi không muốn đụng tới nó, nếu ai có tâm huyết, muốn làm, tôi sẽ hướng dẫn (nghĩa là hướng dẫn tự code, còn source của tôi chỉ dành tặng cho người nào đáp ứng được yêu cầu của Topic 1). Server game chứ đâu phải mấy cái bài prj insert update dữ liệu xuống DB đâu bạn. Chỉ những người nào từng mò làm Server TS rồi mới hiểu, còn những người đem source nước ngoài về modify thì chỉ dừng ở mức độ đó thôi. Ở đây tôi tôn trọng khả năng của DVT nhất, vì code DVT là do bác í tự viết, không phải ngồi chuyển code từ Emu hay j hết.
nếu dc vậy thì tốt wá, tui chỉ rãnh buổi tối tui cũg muốn là 1 sv ts cho riêg mình.tôi kô mở onl chỉ làm để chơi củng bạn bè để ôn lại tuổi thơ ngày nào thui
e hiểu ý bác nói và nhưng lời trên là ý kiến riêng e mong muốn những bác có ý định mở sever, mong rằng sẽ có người đứng ra mở 1 sever cho toàn thể member TSonline của VN cùng vào chơi như sever TSVN ngày trc', chứ ko phải là sever mọc tùm lum như sever MU lậu :(
Ở nc ngoài thì mình không nói làm gì, chứ ở VN việc kiếm 1 người tình nguyện làm 1 việc gì đó cho cộng đồng free là 1 điều vô cùng khó. Chưa kể lúc họ đồng ý 2 điều kiện của bạn rồi bạn, cũng chả dám đảm bảo là khi sv done họ sẽ thực hiện lời hứa. Hi vọng bạn tìm đc người đó....