pat.py 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # SPDX-FileCopyrightText: Copyright (C) 2021-2023 MH3SP Server Project
  4. # SPDX-License-Identifier: AGPL-3.0-or-later
  5. """Monster Hunter PAT module."""
  6. import struct
  7. import traceback
  8. from datetime import timedelta
  9. from other.utils import Logger, get_config, get_ip, hexdump, to_str
  10. import mh.pat_item as pati
  11. import mh.server as server
  12. import mh.time_utils as time_utils
  13. from mh.constants import \
  14. LAYER_CHAT_COLORS, TERMS_VERSION, TERMS, SUBTERMS, ANNOUNCE, \
  15. CHARGE, VULGARITY_INFO, FMP_VERSION, PAT_BINARIES, PAT_NAMES, \
  16. PatID4, get_pat_binary_from_version
  17. from mh.session import Session
  18. import mh.database as db
  19. try:
  20. from typing import Literal, List, Union, Optional # noqa: F401
  21. LayerUserNumUpdate = Literal[1,2,3,4,5]
  22. except ImportError:
  23. pass
  24. g_circle = None
  25. g_circle_info_set = None
  26. class PatServer(server.BasicPatServer, Logger):
  27. """Generic PAT server class."""
  28. def __init__(self, address, handler_class, binary_loader,
  29. max_thread_count=0, logger=None, debug_mode=False,
  30. ssl_cert=None, ssl_key=None):
  31. server.BasicPatServer.__init__(
  32. self, address, handler_class, max_thread_count,
  33. ssl_cert=ssl_cert, ssl_key=ssl_key
  34. )
  35. Logger.__init__(self)
  36. if logger:
  37. self.set_logger(logger)
  38. self.info("Running on {} port {}".format(*address))
  39. self.debug_con = []
  40. self.debug_mode = debug_mode
  41. self.binary_loader = binary_loader
  42. def add_to_debug(self, con):
  43. """Add connection to the debug connection list."""
  44. self.debug_con.append(con)
  45. def del_from_debug(self, con):
  46. """Delete connection from the debug connection list."""
  47. self.debug_con.remove(con)
  48. def get_debug(self):
  49. """Return the debug connection list."""
  50. return self.debug_con
  51. def debug_enabled(self):
  52. return self.debug_mode
  53. def get_pat_handler(self, session):
  54. """Return pat handler from session"""
  55. for handler in self.debug_con:
  56. if handler.session == session:
  57. return handler
  58. return None
  59. def broadcast(self, players, packet_id, data, seq, to_exclude=None):
  60. # type: (db.Players, int, bytes, int, Session|None) -> None
  61. handlers = []
  62. with players.lock():
  63. for _, player in players:
  64. if player == to_exclude:
  65. continue
  66. handler = self.get_pat_handler(player)
  67. if handler:
  68. handlers.append(handler)
  69. for handler in handlers:
  70. handler.try_send_packet(packet_id, data, seq)
  71. def layer_broadcast(self, session, packet_id, data, seq,
  72. exclude_self=True):
  73. # type: (Session, int, bytes, int, bool) -> None
  74. self.broadcast(session.get_layer_players(), packet_id, data, seq,
  75. session if exclude_self else None)
  76. def circle_broadcast(self, circle, packet_id, data, seq,
  77. session=None):
  78. # type: (db.Circle, int, bytes, int, Session|None) -> None
  79. self.broadcast(circle.players, packet_id, data, seq, session)
  80. class PatRequestHandler(server.BasicPatHandler):
  81. """Generic PAT request handler class.
  82. When possible, each packet is described with:
  83. - ID: Packet ID (in hexadecimal)
  84. - JP: Japanese description from the game's packet table
  85. - TR: A roughly translated description
  86. At some point, I'll add packet hexdumps and description for
  87. a better understanding. All descriptions are provided with
  88. the best of our understanding of the packets and might be
  89. inaccurate. `unk` stands for `unknown`.
  90. """
  91. def on_init(self):
  92. """Default PAT handler."""
  93. self.server.info("Handle client from {}".format(self.client_address))
  94. self.server.add_to_debug(self)
  95. self.session = Session(self)
  96. self.ping_timer = time_utils.Timer()
  97. self.requested_connection = False
  98. self.line_check = True
  99. def try_send_packet(self, packet_id=0, data=b'', seq=0):
  100. """Send PAT packet and catch exceptions."""
  101. try:
  102. self.send_packet(packet_id, data, seq)
  103. except Exception:
  104. self.server.warning(
  105. "Failed to send %s[ID=%08x; Seq=%04x]\n%s\n%s",
  106. PAT_NAMES.get(packet_id, "Packet"),
  107. packet_id, seq, traceback.format_exc(), hexdump(data)
  108. )
  109. def try_send_packet_to(self, capcom_id, packet_id=0, data=b'', seq=0):
  110. """Send PAT packet to specific Capcom ID and catch exceptions."""
  111. session = self.session.find_user_by_capcom_id(capcom_id)
  112. if not session:
  113. self.server.warning("Failed to send packet to %s: user not found",
  114. capcom_id)
  115. return
  116. handler = self.server.get_pat_handler(session)
  117. if handler:
  118. handler.try_send_packet(packet_id, data, seq)
  119. def sendAnsNg(self, packet_id, message, seq):
  120. unk1 = 1 # If value is 0, the message is not rendered
  121. data = struct.pack(">I", unk1)
  122. data += pati.lp2_string(message)
  123. packet_id = packet_id | 0xff
  124. self.send_packet(packet_id, data, seq)
  125. def sendAnsAlert(self, packet_id, message, seq):
  126. unk1 = 1 # If value is 0, the message is not rendered
  127. data = struct.pack(">I", unk1)
  128. data += pati.lp2_string(message)
  129. packet_id = packet_id | 0x01
  130. self.send_packet(packet_id, data, seq)
  131. def send_error(self, message, seq=0):
  132. """Send an error message."""
  133. try:
  134. MAX_SIZE = 0x200
  135. MAX_WIDTH = 55
  136. MAX_HEIGHT = 15
  137. LINE_PER_PAGE = min(MAX_HEIGHT, MAX_SIZE // MAX_WIDTH)
  138. lines = [
  139. "<LF=2><BODY><CENTER>A communication error occurred",
  140. "<BR><BODY>Check the server log files for more details",
  141. "<BR><LEFT>",
  142. ] + message.replace("\\", "/").split("\n")
  143. def range_slice(obj, chunk_size):
  144. """Range helper."""
  145. length = len(obj)
  146. return range(length // chunk_size + (length % chunk_size > 0))
  147. def helper(line):
  148. """Split lines helper."""
  149. if len(line) <= MAX_WIDTH:
  150. return [line]
  151. return [
  152. line[i*MAX_WIDTH:(i+1)*MAX_WIDTH]
  153. for i in range_slice(line, MAX_WIDTH)
  154. ]
  155. # Flatten the results
  156. lines = sum([helper(line) for line in lines], [])
  157. for i in range_slice(lines, LINE_PER_PAGE):
  158. seq += 1
  159. message = "<BR><BODY>".join(lines[i*LINE_PER_PAGE:
  160. (i+1)*LINE_PER_PAGE])
  161. # It seems we can't send multiple messages
  162. # self.sendNtcShut("<LF=2><BODY>"+message+"<END>", seq)
  163. self.sendNtcShut(message + "<END>", 0)
  164. # The game will close the connection and the next messages
  165. # won't be received. The except block will be reached if the
  166. # message is too long.
  167. except Exception:
  168. # Probably unreachable and was disconnected
  169. self.server.warning("Failed to send a complete error message")
  170. finally:
  171. self.session.request_reconnection = False
  172. self.finish()
  173. def recvNtcCollectionLog(self, packet_id, data, seq):
  174. """NtcCollectionLog packet.
  175. ID: 60501000
  176. JP: 収集ログ通知
  177. TR: Collection log notification
  178. This packet is sent by the game when an error occurs.
  179. TODO: Find all error codes and their meanings.
  180. Error codes:
  181. - 0x80050037: Unable to find CircleListLayer Slot
  182. - 0x80060002: Fail to warp to location (Layer index error?)
  183. - 0x80070002: Empty NetworkUniqueId?
  184. """
  185. data = pati.CollectionLog.unpack(data)
  186. self.server.debug("CollectionLog: {!r}".format(data))
  187. def sendReqLineCheck(self):
  188. """ReqLineCheck packet.
  189. ID: 60010100
  190. JP: ラインチェック
  191. TR: Line check
  192. The server sends a request to check if the player is still online.
  193. The game will close the connection after 90s, if it doesn't receive it.
  194. """
  195. self.send_packet(PatID4.ReqLineCheck)
  196. def recvAnsLineCheck(self, packet_id, data, seq):
  197. """AnsLineCheck packet.
  198. ID: 60010200
  199. JP: ラインチェック
  200. TR: Line check
  201. The game sends this packet after receiving a ReqLineCheck packet.
  202. """
  203. self.line_check = True
  204. def sendReqConnection(self, unused=0, seq=0):
  205. """ReqConnection packet.
  206. ID: 60200100
  207. JP: PAT接続環境要求
  208. TR: PAT connection settings request
  209. The server sends a request to the game to establish a PAT connection.
  210. It also sends a parameter that seems unused on the western versions.
  211. """
  212. data = struct.pack(">I", unused)
  213. self.send_packet(PatID4.ReqConnection, data, seq)
  214. def recvAnsConnection(self, packet_id, data, seq):
  215. """AnsConnection packet.
  216. ID: 60200200
  217. JP: PAT接続環境返答
  218. TR: PAT connection settings response
  219. The games sends the PAT environment properties.
  220. """
  221. settings = pati.ConnectionData.unpack(data)
  222. self.server.debug("Connection: {!r}".format(settings))
  223. pat_ticket = b""
  224. if "pat_ticket" in settings:
  225. _, pat_ticket = pati.unpack_any(settings.pat_ticket)
  226. elif "online_support_code" in settings:
  227. _, pat_ticket = pati.unpack_any(settings.online_support_code)
  228. self.server.info("Client {} Ticket `{}`".format(self.client_address,
  229. pat_ticket))
  230. self.sendNtcLogin(5, settings, seq)
  231. def sendNtcLogin(self, server_status, connection_data, seq):
  232. """NtcLogin packet.
  233. ID: 60211000
  234. JP: ログイン処理概要通知
  235. TR: Login process summary notification
  236. The server sends upon login a notification with the server status.
  237. """
  238. data = struct.pack(">B", server_status)
  239. self.session = self.session.get(connection_data)
  240. self.send_packet(PatID4.NtcLogin, data, seq)
  241. def recvReqAuthenticationToken(self, packet_id, data, seq):
  242. """ReqAuthenticationToken packet.
  243. ID: 62600100
  244. JP: 認証トークン送信
  245. TR: Send authentication token
  246. The games requests a PAT authentication by forwarding the token
  247. obtained from Nintendo NAS server.
  248. """
  249. nas_token = pati.unpack_lp2_string(data)
  250. self.server.info("Client {} - NAS `{}`".format(self.client_address,
  251. nas_token))
  252. self.sendAnsAuthenticationToken(nas_token, seq)
  253. def sendAnsAuthenticationToken(self, nas_token, seq):
  254. """AnsAuthenticationToken packet.
  255. ID: 62600200
  256. JP: 認証トークン返答
  257. TR: Authentication token response
  258. The server replies this packet to acknowledge the authentication.
  259. """
  260. self.send_packet(PatID4.AnsAuthenticationToken, b'', seq)
  261. def recvReqTermsVersion(self, packet_id, data, seq):
  262. """ReqTermsVersion packet.
  263. ID: 62100100
  264. JP: 利用規約情報確認
  265. TR: Terms of use information verification
  266. The game requests the terms version and its total size.
  267. """
  268. self.sendAnsTermsVersion(TERMS_VERSION, len(TERMS[TERMS_VERSION]), seq)
  269. def sendAnsTermsVersion(self, terms_version, terms_size, seq):
  270. """AnsTermsVersion packet.
  271. ID: 62100200
  272. JP: 利用規約情報応答
  273. TR: Terms of use information response
  274. The server replies with the terms version and total size.
  275. """
  276. data = struct.pack(">II", terms_version, terms_size)
  277. self.send_packet(PatID4.AnsTermsVersion, data, seq)
  278. def recvReqTerms(self, packet_id, data, seq):
  279. """ReqTerms packet.
  280. ID: 62110100
  281. JP: 利用規約要求
  282. TR: Terms of use request
  283. The game requests the terms based on what it has already read.
  284. """
  285. version, offset, size = struct.unpack(">III", data)
  286. self.sendAnsTerms(offset, size, TERMS[version], seq)
  287. def sendAnsTerms(self, offset, size, terms, seq):
  288. """AnsTerms packet.
  289. ID: 62110200
  290. JP: 利用規約応答
  291. TR: Terms of use response
  292. The server replies with the terms offset, size and chunk requested.
  293. """
  294. data = struct.pack(">II", offset, size)
  295. data += pati.lp2_string(terms[offset:offset+size])
  296. self.send_packet(PatID4.AnsTerms, data, seq)
  297. def recvReqSubTermsInfo(self, packet_id, data, seq):
  298. """ReqSubTermsInfo european packet.
  299. ID: 62130100
  300. JP: サブ利用規約指定情報確認
  301. TR: Sub-terms of use information verification
  302. The game requests the sub-terms info.
  303. """
  304. unk, = struct.unpack(">B", data)
  305. self.sendAnsSubTermsInfo(unk, len(SUBTERMS[TERMS_VERSION]), seq)
  306. def sendAnsSubTermsInfo(self, unk, size, seq):
  307. """AnsSubTermsInfo european packet.
  308. ID: 62130200
  309. JP: サブ利用規約指定情報応答
  310. TR: Sub-terms of use information response
  311. The server acknowledges the request.
  312. """
  313. unk1 = 1
  314. data = struct.pack(">IBI", unk1, unk, size)
  315. self.send_packet(PatID4.AnsSubTermsInfo, data, seq)
  316. def recvReqSubTerms(self, packet_id, data, seq):
  317. """ReqSubTerms european packet.
  318. ID: 62140100
  319. JP: 利用規約要求
  320. TR: Sub-terms of use request
  321. The game requests the sub-terms based on what it has already read.
  322. """
  323. version, unk, offset, size = struct.unpack(">IBII", data)
  324. assert version == TERMS_VERSION, "Terms and subterms version mismatch"
  325. self.sendAnsSubTerms(unk, offset, size, SUBTERMS[version], seq)
  326. def sendAnsSubTerms(self, unk, offset, size, subterms, seq):
  327. """AnsSubTerms european packet.
  328. ID: 62140200
  329. JP: サブ利用規約応答
  330. TR: Sub-terms of use response
  331. The server replies with the terms offset, size and chunk requested.
  332. """
  333. data = struct.pack(">BII", unk, offset, size)
  334. data += pati.lp2_string(subterms[offset:offset+size])
  335. self.send_packet(PatID4.AnsSubTerms, data, seq)
  336. def recvReqAnnounce(self, packet_id, data, seq):
  337. """ReqAnnounce packet.
  338. ID: 62300100
  339. JP: お知らせ要求
  340. TR: Notice request
  341. The game requests the announce text.
  342. """
  343. self.sendAnsAnnounce(ANNOUNCE, seq)
  344. def sendAnsAnnounce(self, announce, seq):
  345. """AnsAnnounce packet.
  346. ID: 62300200
  347. JP: お知らせ通知
  348. TR: Notice response
  349. The server replies with the announce text.
  350. """
  351. data = pati.lp2_string(announce)
  352. self.send_packet(PatID4.AnsAnnounce, data, seq)
  353. def recvReqNoCharge(self, packet_id, data, seq):
  354. """ReqNoCharge packet.
  355. ID: 62310100
  356. JP: 未課金メッセージ要求
  357. TR: Unpaid message request
  358. The game requests the no-charge text.
  359. NB:
  360. - Japanese servers were online paid.
  361. - Western servers were free-to-play.
  362. """
  363. self.sendAnsNoCharge(CHARGE, seq)
  364. def sendAnsNoCharge(self, no_charge, seq):
  365. """AnsNoCharge packet.
  366. ID: 62310200
  367. JP: 未課金メッセージ通知
  368. TR: Unpaid message response
  369. The server replies with the no-charge text.
  370. """
  371. data = pati.lp2_string(no_charge)
  372. self.send_packet(PatID4.AnsNoCharge, data, seq)
  373. def recvReqVulgarityInfoHighJAP(self, packet_id, data, seq):
  374. """ReqVulgarityInfoHigh japanese packet.
  375. ID: 62500100
  376. JP: 名前用禁止文言要求
  377. TR: Forbidden names request
  378. """
  379. self.sendAnsVulgarityInfoHighJAP(seq)
  380. def sendAnsVulgarityInfoHighJAP(self, seq):
  381. """AnsVulgarityInfoHigh japanese packet.
  382. ID: 62500200
  383. JP: 名前用禁止文言応答
  384. TR: Forbidden names response
  385. """
  386. unk = 1
  387. data = struct.pack(">II", unk, len(VULGARITY_INFO))
  388. self.send_packet(PatID4.AnsVulgarityInfoHighJAP, data, seq)
  389. def recvReqVulgarityInfoLowJAP(self, packet_id, data, seq):
  390. """ReqVulgarityInfoLow japanese packet.
  391. ID: 62520100
  392. JP: 名前以外用禁止文言要求
  393. TR: Forbidden words request
  394. """
  395. self.sendAnsVulgarityInfoLowJAP(seq)
  396. def sendAnsVulgarityInfoLowJAP(self, seq):
  397. """AnsVulgarityInfoLow japanese packet.
  398. ID: 62520200
  399. JP: 名前以外用禁止文言応答
  400. TR: Forbidden words response
  401. """
  402. unk = 1
  403. data = struct.pack(">II", unk, len(VULGARITY_INFO))
  404. self.send_packet(PatID4.AnsVulgarityInfoLowJAP, data, seq)
  405. def recvReqVulgarityInfoLow(self, packet_id, data, seq):
  406. """ReqVulgarityInfoLow packet.
  407. ID: 62560100
  408. JP: 真・名前以外用禁止文言要求
  409. TR: (New) Forbidden words request
  410. """
  411. info, = struct.unpack(">I", data)
  412. self.sendAnsVulgarityInfoLow(info, seq)
  413. def sendAnsVulgarityInfoLow(self, info, seq):
  414. """AnsVulgarityInfoLow packet.
  415. ID: 62560200
  416. JP: 真・名前以外用禁止文言応答
  417. TR: (New) Forbidden words response
  418. """
  419. unk = 1
  420. data = struct.pack(">III", unk, info, len(VULGARITY_INFO))
  421. self.send_packet(PatID4.AnsVulgarityInfoLow, data, seq)
  422. def recvReqVulgarityLow(self, packet_id, data, seq):
  423. """ReqVulgarityLow packet.
  424. ID: 62570100
  425. JP: 真・名前以外用禁止文言取得要求
  426. TR: (New) Get forbidden words request
  427. """
  428. unk, info, offset, size = struct.unpack(">IIII", data)
  429. self.sendAnsVulgarityLow(
  430. info, offset, size, VULGARITY_INFO, seq
  431. )
  432. def sendAnsVulgarityLow(self, info, offset, size, vulg, seq):
  433. """AnsVulgarityLow packet.
  434. ID: 62570200
  435. JP: 真・名前以外用禁止文言取得応答
  436. TR: (New) Get forbidden words response
  437. """
  438. data = struct.pack(">III", info, offset, size)
  439. data += pati.lp2_string(vulg)
  440. self.send_packet(PatID4.AnsVulgarityLow, data, seq)
  441. def recvReqCommonKey(self, packet_id, data, seq):
  442. """ReqCommonKey packet.
  443. ID: 60700100
  444. JP: 共通鍵要求
  445. TR: Common key request
  446. """
  447. self.sendAnsCommonKey(seq)
  448. def sendAnsCommonKey(self, seq):
  449. """AnsCommonKey packet.
  450. ID: 60700200
  451. JP: 共通鍵返答
  452. TR: Common key response
  453. TODO: Handle encryption properly.
  454. """
  455. # Bypass upcoming encryption by sending a dummy packet instead
  456. # self.send_packet(PatID4.AnsCommonKey, b'', seq)
  457. self.sendAnsAuthenticationToken(b'', seq)
  458. def recvReqLmpConnect(self, packet_id, data, seq):
  459. """ReqLmpConnect packet.
  460. ID: 62010100
  461. JP: LMPの接続先要求
  462. TR: LMP's access point request
  463. TODO: I don't think it's related to LMP protocol.
  464. """
  465. config = get_config("LMP")
  466. self.sendAnsLmpConnect(get_ip(config["IP"]), config["Port"], seq)
  467. def sendAnsLmpConnect(self, address, port, seq):
  468. """AnsLmpConnect packet.
  469. ID: 62010200
  470. JP: LMPの接続先応答
  471. TR: LMP's access point response
  472. TODO: Handle/Convert special addresses like 127.0.0.1 and 0.0.0.0.
  473. """
  474. data = struct.pack(">H", len(address))
  475. data += address.encode("ascii")
  476. data += struct.pack(">H", port)
  477. self.send_packet(PatID4.AnsLmpConnect, data, seq)
  478. def recvReqShut(self, packet_id, data, seq):
  479. """ReqShut packet.
  480. ID: 60100100
  481. JP: 切断要求
  482. TR: Disconnection request
  483. # 1: full logout(?)
  484. # 2: logout to different server(?)
  485. """
  486. shutdown_type, = struct.unpack(">B", data)
  487. self.sendAnsShut(shutdown_type, seq)
  488. def sendAnsShut(self, shutdown_type, seq):
  489. """AnsShut packet.
  490. ID: 60100200
  491. JP: 切断返答
  492. TR: Disconnection response
  493. """
  494. data = struct.pack(">B", shutdown_type)
  495. self.send_packet(PatID4.AnsShut, data, seq)
  496. if shutdown_type == 1:
  497. # Only modify request_reconnection if it's a 1 shutdown_type,
  498. # otherwise leave it at what it was before
  499. self.session.request_reconnection = False
  500. self.finish()
  501. def sendNtcShut(self, message, seq):
  502. """NtcShut packet.
  503. ID: 60101000
  504. JP: 切断返答
  505. TR: Disconnection notification
  506. """
  507. has_message = bool(message)
  508. data = struct.pack(">B", int(has_message))
  509. data += pati.lp2_string(message[:0x200])
  510. self.send_packet(PatID4.NtcShut, data, seq)
  511. def recvReqChargeInfo(self, packet_id, data, seq):
  512. """ReqChargeInfo packet.
  513. ID: 61020100
  514. JP: 課金情報要求
  515. TR: Billing information request
  516. """
  517. info_type, = struct.unpack('>B', data)
  518. self.sendAnsChargeInfo(info_type, seq)
  519. def sendAnsChargeInfo(self, info_type, seq):
  520. """AnsChargeInfo packet.
  521. ID: 61020200
  522. JP: 課金情報返答
  523. TR: Billing information response
  524. """
  525. info = pati.ChargeInfo()
  526. info.ticket_validity1 = pati.Long(
  527. int(timedelta(days=1).total_seconds())
  528. )
  529. info.ticket_validity2 = pati.Long(
  530. int(timedelta(days=1).total_seconds())
  531. )
  532. info.unk_binary_0x05 = pati.Binary("Cid")
  533. info.online_support_code = pati.String(self.session.get_support_code())
  534. data = info.pack()
  535. self.send_packet(PatID4.AnsChargeInfo, data, seq)
  536. def recvReqLoginInfo(self, packet_id, data, seq):
  537. """ReqLoginInfo packet.
  538. ID: 61010100
  539. JP: ログイン情報送信
  540. TR: Send login information
  541. """
  542. data = pati.LoginInfo.unpack(data)
  543. self.server.debug("LoginInfo: {!r}".format(data))
  544. self.sendAnsLoginInfo(seq)
  545. def sendAnsLoginInfo(self, seq):
  546. """AnsLoginInfo packet.
  547. ID: 61010200
  548. JP: ログイン情報返信
  549. TR: Login information response
  550. TODO: Implement this properly.
  551. """
  552. need_ticket = 1 # The game will call sendReqTicket if set to 1
  553. data = struct.pack(">B", need_ticket)
  554. data += pati.lp2_string("dummy_data")
  555. info = pati.ChargeInfo()
  556. info.online_support_code = pati.String(
  557. self.session.get_support_code())
  558. data += info.pack()
  559. self.send_packet(PatID4.AnsLoginInfo, data, seq)
  560. def recvReqTicket(self, packet_id, data, seq):
  561. """ReqTicket packet.
  562. ID: 60300100
  563. JP: PATチケット要求
  564. TR: PAT ticket request
  565. It seems both the client and server can:
  566. - Send a PAT ticket
  567. - Receive a PAT ticket
  568. TODO: Investigate how PAT tickets should be used.
  569. """
  570. if packet_id == PatID4.ReqTicket:
  571. self.sendAnsTicket(seq)
  572. elif packet_id == PatID4.ReqTicket2:
  573. self.server.error("Unimplemented recvReqTicket")
  574. def sendAnsTicket(self, seq):
  575. """AnsTicket packet.
  576. ID: 60300200
  577. JP: PATチケット返答
  578. TR: PAT ticket response
  579. """
  580. pat_ticket = self.session.new_pat_ticket()
  581. data = struct.pack(">H", len(pat_ticket)) + pat_ticket
  582. self.send_packet(PatID4.AnsTicket, data, seq)
  583. def recvReqUserListHead(self, packet_id, data, seq):
  584. """ReqUserListHead packet.
  585. ID: 61100100
  586. JP: PAT ID候補数要求
  587. TR: PAT ID candidate count request
  588. The games' instruction leaflets seem to refer "PAT ID" as "Capcom ID".
  589. """
  590. first_index, count = struct.unpack_from(">II", data)
  591. header = pati.unpack_bytes(data, 8)
  592. self.sendAnsUserListHead(first_index, count, header, seq)
  593. def sendAnsUserListHead(self, first_index, count, header, seq):
  594. """AnsUserListHead packet.
  595. ID: 61100200
  596. JP: PAT ID候補数応答
  597. TR: PAT ID candidate count response
  598. """
  599. data = struct.pack(">II", first_index, count)
  600. self.send_packet(PatID4.AnsUserListHead, data, seq)
  601. def recvReqUserListData(self, packet_id, data, seq):
  602. """ReqUserListData packet.
  603. ID: 61110100
  604. JP: PAT ID候補要求
  605. TR: PAT ID candidate request
  606. """
  607. first_index, count = struct.unpack(">II", data)
  608. self.sendAnsUserListData(first_index, count, seq)
  609. def sendAnsUserListData(self, first_index, count, seq):
  610. """AnsUserListData packet.
  611. ID: 61110200
  612. JP: PAT ID候補送信
  613. TR: Send PAT ID candidate
  614. TODO: Properly create/save/load Capcom ID profiles.
  615. """
  616. data = struct.pack(">II", first_index, count)
  617. for i, obj in self.session.get_users(first_index, count):
  618. capcom_id, info = obj
  619. user = pati.UserObject()
  620. user.slot_index = pati.Long(i)
  621. user.capcom_id = pati.String(capcom_id)
  622. if info.get("name"):
  623. user.hunter_name = pati.String(info["name"])
  624. data += user.pack()
  625. self.send_packet(PatID4.AnsUserListData, data, seq)
  626. def recvReqUserListFoot(self, packet_id, data, seq):
  627. """ReqUserList packet.
  628. ID: 61120100
  629. JP: PAT ID候補送信終了確認
  630. TR: PAT ID candidate end of transmission request
  631. """
  632. self.sendAnsUserListFoot(seq)
  633. def sendAnsUserListFoot(self, seq):
  634. """AnsUserListFoot packet.
  635. ID: 61120200
  636. JP: PAT ID候補送信終了返答
  637. TR: PAT ID candidate end of transmission response
  638. """
  639. self.send_packet(PatID4.AnsUserListFoot, b"", seq)
  640. def recvReqServerTime(self, packet_id, data, seq):
  641. """ReqServerTime packet.
  642. ID: 60020100
  643. JP: サーバ時刻要求
  644. TR: Server time request
  645. """
  646. converted_country_code, = struct.unpack(">I", data)
  647. self.sendAnsServerTime(converted_country_code, seq)
  648. def sendAnsServerTime(self, converted_country_code, seq):
  649. """AnsServerTime packet.
  650. ID: 60020200
  651. JP: サーバ時刻返答
  652. TR: Server time response
  653. """
  654. # Counter that ticks up once per second, Epoch works
  655. server_time = time_utils.current_server_time()
  656. # Always Epoch, used for Wii Shop subscription ticket
  657. current_time = time_utils.current_server_time()
  658. data = struct.pack(">II", server_time, current_time)
  659. self.send_packet(PatID4.AnsServerTime, data, seq)
  660. def recvReqUserObject(self, packet_id, data, seq):
  661. """ReqUserObject packet.
  662. ID: 61200100
  663. JP: ユーザオブジェクト送信
  664. TR: Send user object
  665. TODO: Find the purpose of all UserObject fields.
  666. """
  667. is_slot_empty, slot_index = struct.unpack_from(">BI", data)
  668. user_obj = pati.UserObject.unpack(data, 5)
  669. self.server.debug("UserObject: {}, {}, {!r}".format(
  670. is_slot_empty, slot_index, user_obj
  671. ))
  672. hunter_name = None
  673. if hasattr(user_obj, "hunter_name"):
  674. hunter_name = pati.unpack_string(user_obj.hunter_name)
  675. self.session.use_user(slot_index, hunter_name)
  676. user_obj.capcom_id = pati.String(self.session.capcom_id)
  677. self.server.info("Client {} Capcom ID `{}`".format(
  678. self.client_address, self.session.capcom_id
  679. ))
  680. self.sendAnsUserObject(is_slot_empty, slot_index, user_obj, seq)
  681. def sendAnsUserObject(self, is_slot_empty, slot_index, user_obj, seq):
  682. """AnsUserObject packet.
  683. ID: 61200200
  684. JP: ユーザオブジェクト結果
  685. TR: User object result
  686. TODO: Properly store/update user objects.
  687. """
  688. unused = 0
  689. need_ticket = 1
  690. data = struct.pack(">B", need_ticket)
  691. data += pati.lp2_string(b"Unk_UserObj_str")
  692. data += struct.pack(">I", unused)
  693. data += user_obj.pack()
  694. self.send_packet(PatID4.AnsUserObject, data, seq)
  695. def recvReqFmpListVersion(self, packet_id, data, seq):
  696. """ReqFmpListVersion packet.
  697. ID: 61300100 / 63100100
  698. JP: FMPリストバージョン確認
  699. TR: FMP list version check
  700. TODO:
  701. - Find why there are 2 versions of FMP packets.
  702. - Find why most of the 2 versions are ignored.
  703. """
  704. if packet_id == PatID4.ReqFmpListVersion:
  705. self.sendAnsFmpListVersion(seq)
  706. elif packet_id == PatID4.ReqFmpListVersion2:
  707. self.sendAnsFmpListVersion2(seq)
  708. def sendAnsFmpListVersion(self, seq):
  709. """AnsFmpListVersion packet.
  710. ID: 61300200
  711. JP: FMPリストバージョン確認応答
  712. TR: FMP list version acknowledgment
  713. """
  714. data = struct.pack(">I", FMP_VERSION)
  715. self.send_packet(PatID4.AnsFmpListVersion, data, seq)
  716. def sendAnsFmpListVersion2(self, seq):
  717. """AnsFmpListVersion2 packet.
  718. ID: 63100200
  719. JP: FMPリストバージョン確認応答
  720. TR: FMP list version acknowledgment
  721. """
  722. data = struct.pack(">I", FMP_VERSION)
  723. self.send_packet(PatID4.AnsFmpListVersion2, data, seq)
  724. def recvReqFmpListHead(self, packet_id, data, seq):
  725. """ReqFmpListHead packet.
  726. ID: 61310100 / 63110100
  727. JP: FMPリスト数送信 / FMPリスト数要求
  728. TR: Send FMP list count / FMP list count request
  729. """
  730. # TODO: Might be worth investigating these parameters as
  731. # they might be useful when using multiple FMP servers.
  732. version, first_index, count = struct.unpack_from(
  733. ">III", data
  734. ) # noqa: F841
  735. # TODO: Unpack it using pati.Unpacker
  736. header = pati.unpack_bytes(data, 12) # noqa: F841
  737. if packet_id == PatID4.ReqFmpListHead:
  738. self.sendAnsFmpListHead(seq)
  739. elif packet_id == PatID4.ReqFmpListHead2:
  740. self.sendAnsFmpListHead2(seq)
  741. def sendAnsFmpListHead(self, seq):
  742. """AnsFmpListHead packet.
  743. ID: 61310200
  744. JP: FMPリスト数応答
  745. TR: FMP list count response
  746. """
  747. unused = 0
  748. count = len(self.session.get_servers())
  749. data = struct.pack(">II", unused, count)
  750. self.send_packet(PatID4.AnsFmpListHead, data, seq)
  751. def sendAnsFmpListHead2(self, seq):
  752. """AnsFmpListHead2 packet.
  753. ID: 63110200
  754. JP: FMPリスト数応答
  755. TR: FMP list count response
  756. TODO: Check if it's always ignored compared to the previous one.
  757. """
  758. unused = 0
  759. count = len(self.session.get_servers())
  760. data = struct.pack(">II", unused, count)
  761. self.send_packet(PatID4.AnsFmpListHead2, data, seq)
  762. def recvReqFmpListData(self, packet_id, data, seq):
  763. """ReqFmpListData packet.
  764. ID: 61320100 / 63120100
  765. JP: FMPリスト送信 / FMPリスト要求
  766. TR: Send FMP list / FMP list response
  767. """
  768. first_index, count = struct.unpack_from(">II", data)
  769. if packet_id == PatID4.ReqFmpListData:
  770. self.sendAnsFmpListData(first_index, count, seq)
  771. elif packet_id == PatID4.ReqFmpListData2:
  772. self.sendAnsFmpListData2(first_index, count, seq)
  773. def sendAnsFmpListData(self, first_index, count, seq):
  774. """AnsFmpListData packet.
  775. ID: 61320200
  776. JP: FMPリスト応答
  777. TR: FMP list response
  778. TODO:
  779. - Do more reverse engineering.
  780. - This packet seems to affect only the first entry.
  781. """
  782. unused = 0
  783. data = struct.pack(">II", unused, count)
  784. data += pati.get_fmp_servers(self.session, first_index, count)
  785. self.send_packet(PatID4.AnsFmpListData, data, seq)
  786. def sendAnsFmpListData2(self, first_index, count, seq):
  787. """AnsFmpListData2 packet.
  788. ID: 63120200
  789. JP: FMPリスト応答
  790. TR: FMP list response
  791. TODO:
  792. - Do more reverse engineering.
  793. - This packet seems to affect entries past the first one.
  794. """
  795. unused = 0
  796. data = struct.pack(">II", unused, count)
  797. data += pati.get_fmp_servers(self.session, first_index, count)
  798. self.send_packet(PatID4.AnsFmpListData2, data, seq)
  799. def recvReqFmpListFoot(self, packet_id, data, seq):
  800. """ReqFmpListFoot packet.
  801. ID: 61330100 / 63130100
  802. JP: FMPリスト送信終了 / FMPリスト終了送信
  803. TR: FMP list end of transmission / FMP list transmission end
  804. """
  805. if packet_id == PatID4.ReqFmpListFoot:
  806. self.sendAnsFmpListFoot(seq)
  807. elif packet_id == PatID4.ReqFmpListFoot2:
  808. self.sendAnsFmpListFoot2(seq)
  809. def sendAnsFmpListFoot(self, seq):
  810. """AnsFmpListFoot packet.
  811. ID: 61330200
  812. JP: FMPリスト送信終了
  813. TR: FMP list end of transmission
  814. """
  815. self.send_packet(PatID4.AnsFmpListFoot, b"", seq)
  816. def sendAnsFmpListFoot2(self, seq):
  817. """AnsFmpListFoot2 packet.
  818. ID: 63130200
  819. JP: FMPリスト終了返答
  820. TR: FMP list end of transmission response
  821. """
  822. self.send_packet(PatID4.AnsFmpListFoot2, b"", seq)
  823. def recvReqLayerEnd(self, packet_id, data, seq):
  824. """ReqLayerEnd packet.
  825. ID: 64020100
  826. JP: レイヤ終了要求
  827. TR: Layer end request
  828. """
  829. self.sendAnsLayerEnd(seq)
  830. def sendAnsLayerEnd(self, seq):
  831. """AnsLayerEnd packet.
  832. ID: 64020200
  833. JP: レイヤ終了応答
  834. TR: Layer end response
  835. """
  836. self.notify_layer_departure(True)
  837. self.send_packet(PatID4.AnsLayerEnd, b"", seq)
  838. @staticmethod
  839. def packNtcLayerUserNum(update_type, layer_data):
  840. # type: (LayerUserNumUpdate, pati.LayerData) -> bytes
  841. """NtcLayerUserNum packet.
  842. ID: NtcLayerUserNum
  843. JP: レイヤ人数通知
  844. TR: Layer number notification
  845. UPDATE TYPE:
  846. 1 - Update numbers in the current layer
  847. 2 - Update numbers in the current layer plus fire an event (unknown)
  848. 3 - Update numbers in an unknown struct in an array
  849. 4 - Update numbers to the current layer's child (child_id=layer_path)
  850. 5 - Update numbers in unk fields in the NetworkLayerPat struct
  851. """
  852. data = struct.pack(">B", update_type)
  853. data += pati.LayerUserNum.pack_from(layer_data)
  854. return data
  855. def recvReqFmpInfo(self, packet_id, data, seq):
  856. """ReqFmpInfo packet.
  857. ID: 61340100 / 63140100
  858. JP: FMPデータ要求 / FMPデータ要求
  859. TR: FMP data request
  860. TODO: Do not hardcode the data and find the meaning of all fields.
  861. """
  862. index, = struct.unpack_from(">I", data)
  863. fields = pati.unpack_bytes(data, 4)
  864. server = self.session.join_server(index)
  865. config = get_config("FMP")
  866. fmp_addr = get_ip(config["IP"])
  867. fmp_port = config["Port"]
  868. fmp_data = pati.FmpData()
  869. fmp_data.server_address = pati.String(server.addr or fmp_addr)
  870. fmp_data.server_port = pati.Word(server.port or fmp_port)
  871. fmp_data.assert_fields(fields)
  872. if packet_id == PatID4.ReqFmpInfo:
  873. self.sendAnsFmpInfo(fmp_data, fields, seq)
  874. elif packet_id == PatID4.ReqFmpInfo2:
  875. self.sendAnsFmpInfo2(fmp_data, fields, seq)
  876. # Preserve session in database, due to server selection
  877. self.session.request_reconnection = True
  878. def sendAnsFmpInfo(self, fmp_data, fields, seq):
  879. """AnsFmpInfo packet.
  880. ID: 61340200
  881. JP: FMPデータ返答
  882. TR: FMP data response
  883. """
  884. data = fmp_data.pack_fields(fields)
  885. self.send_packet(PatID4.AnsFmpInfo, data, seq)
  886. def sendAnsFmpInfo2(self, fmp_data, fields, seq):
  887. """AnsFmpInfo2 packet.
  888. ID: 63140200
  889. JP: FMPデータ返答
  890. TR: FMP data response
  891. """
  892. data = fmp_data.pack_fields(fields)
  893. self.send_packet(PatID4.AnsFmpInfo2, data, seq)
  894. def recvReqBinaryHead(self, packet_id, data, seq):
  895. """ReqBinaryHead packet.
  896. ID: 63020100
  897. JP: バイナリデータ開始要求
  898. TR: Binary data start request
  899. TODO: Find all binary types and their meaning.
  900. """
  901. binary_type, = struct.unpack(">B", data)
  902. self.sendAnsBinaryHead(binary_type, seq)
  903. def sendAnsBinaryHead(self, binary_type, seq):
  904. """AnsBinaryHead packet.
  905. ID: 63020200
  906. JP: バイナリデータ開始応答
  907. TR: Binary data start response
  908. Examples of types sent during the login process
  909. - English: 0x05, 0x01, 0x05, 0x02, 0x03, 0x04
  910. - Japanese: 0x0a, 0x01, 0x0a, 0x02, 0x03, 0x04
  911. - French: 0x14, 0x10, 0x14, 0x11, 0x12, 0x13
  912. - German: 0x23, 0x1f, 0x23, 0x20, 0x21, 0x22
  913. - Italian: 0x32, 0x2e, 0x32, 0x2f, 0x30, 0x31
  914. - Spanish: 0x41, 0x3d, 0x41, 0x3e, 0x3f, 0x40
  915. """
  916. binary = PAT_BINARIES[binary_type]
  917. version = binary["version"]
  918. if callable(version):
  919. version = version(self.server.binary_loader)
  920. content = get_pat_binary_from_version(binary_type, version)
  921. if callable(content):
  922. content = content(self.server.binary_loader)
  923. data = struct.pack(">II", version, len(content))
  924. self.send_packet(PatID4.AnsBinaryHead, data, seq)
  925. def recvReqBinaryData(self, packet_id, data, seq):
  926. """ReqBinaryData packet.
  927. ID: 63030100
  928. JP: バイナリデータ要求
  929. TR: Binary data request
  930. """
  931. binary_type, version, offset, size = struct.unpack(">BIII", data)
  932. content = get_pat_binary_from_version(binary_type, version)
  933. if callable(content):
  934. content = content(self.server.binary_loader)
  935. self.sendAnsBinaryData(version, offset, size, content, seq)
  936. def sendAnsBinaryData(self, version, offset, size, binary, seq):
  937. """AnsBinaryData packet.
  938. ID: 63030200
  939. JP: バイナリデータ応答
  940. TR: Binary data response
  941. """
  942. data = struct.pack(">III", version, offset, size)
  943. data += pati.lp2_string(binary[offset:offset+size])
  944. self.send_packet(PatID4.AnsBinaryData, data, seq)
  945. def recvReqBinaryFoot(self, packet_id, data, seq):
  946. """ReqBinaryFoot packet.
  947. ID: 63040100
  948. JP: バイナリデータ完了要求
  949. TR: Binary date end of transmission request
  950. """
  951. binary_type, = struct.unpack(">B", data)
  952. self.sendAnsBinaryFoot(binary_type, seq)
  953. def sendAnsBinaryFoot(self, binary_type, seq):
  954. """AnsBinaryData packet.
  955. ID: 63040200
  956. JP: バイナリデータ完了応答
  957. TR: Binary date end of transmission response
  958. """
  959. self.send_packet(PatID4.AnsBinaryFoot, b"", seq)
  960. def recvReqUserSearchHead(self, packet_id, data, seq):
  961. """ReqUserSearchHead packet.
  962. ID: 66330100
  963. JP: ユーザ検索数要求
  964. TR: User search count request
  965. Sent by the game when searching for players:
  966. - Online > Player Search > By Name
  967. - Online > Player Search > By Id
  968. """
  969. with pati.Unpacker(data) as unpacker:
  970. self.search_info = {
  971. "capcom_id": to_str(unpacker.lp2_string()),
  972. "hunter_name": unpacker.lp2_string(),
  973. "search": unpacker.detailed_optional_fields(),
  974. "offset": unpacker.struct(">I")[0],
  975. "limit": unpacker.struct(">I")[0],
  976. "fields": unpacker.bytes()
  977. }
  978. self.server.debug((
  979. "ReqUserSearchHead("
  980. "hunter_name={hunter_name!r}, capcom_id={capcom_id!r}, "
  981. "search={search!r}, offset={offset}, limit={limit}, "
  982. "fields={fields!r})"
  983. ).format(**self.search_info))
  984. self.sendAnsUserSearchHead(seq)
  985. def sendAnsUserSearchHead(self, seq):
  986. """AnsUserSearchHead packet.
  987. ID: 66330200
  988. JP: ユーザ検索数返答
  989. TR: User search count response
  990. """
  991. unk = 0
  992. self.search_data = self.session.find_users(
  993. self.search_info["capcom_id"], self.search_info["hunter_name"],
  994. self.search_info["offset"], self.search_info["limit"]
  995. )
  996. data = struct.pack(">II", unk, len(self.search_data))
  997. self.send_packet(PatID4.AnsUserSearchHead, data, seq)
  998. def recvReqUserSearchData(self, packet_id, data, seq):
  999. """ReqUserSearchData packet.
  1000. ID: 66340100
  1001. JP: ユーザ検索要求
  1002. TR: User search request
  1003. """
  1004. offset, size = struct.unpack(">II", data)
  1005. self.sendAnsUserSearchData(offset, size, seq)
  1006. def sendAnsUserSearchData(self, offset, size, seq):
  1007. """AnsUserSearchData packet.
  1008. ID: 66340200
  1009. JP: ユーザ検索返答
  1010. TR: User search response
  1011. """
  1012. unk = 0
  1013. users = self.search_data
  1014. count = len(users)
  1015. data = struct.pack(">II", unk, count)
  1016. for user in users:
  1017. user_info = pati.UserSearchInfo()
  1018. user_info.capcom_id = pati.String(user.capcom_id)
  1019. user_info.hunter_name = pati.String(user.hunter_name)
  1020. user_info.stats = pati.Binary(user.hunter_info.pack())
  1021. user_info.layer_host = pati.Binary(user.get_layer_host_data())
  1022. user_info.assert_fields(self.search_info["fields"])
  1023. data += user_info.pack()
  1024. data += pati.pack_optional_fields(user.get_optional_fields())
  1025. self.send_packet(PatID4.AnsUserSearchData, data, seq)
  1026. def recvReqUserSearchFoot(self, packet_id, data, seq):
  1027. """ReqUserSearchFoot packet.
  1028. ID: 66350100
  1029. JP: ユーザ検索終了要求
  1030. TR: User search end of transmission request
  1031. """
  1032. self.sendAnsUserSearchFoot(seq)
  1033. def sendAnsUserSearchFoot(self, seq):
  1034. """AnsUserSearchFoot packet.
  1035. ID: 66350200
  1036. JP: ユーザ検索終了返答
  1037. TR: User search end of transmission response
  1038. """
  1039. self.send_packet(PatID4.AnsUserSearchFoot, b"", seq)
  1040. def recvReqUserSearchInfo(self, packet_id, data, seq):
  1041. """ReqUserSearchInfo packet.
  1042. ID: 66360100
  1043. JP: ユーザ検索データ要求
  1044. TR: User search data request
  1045. """
  1046. with pati.Unpacker(data) as unpacker:
  1047. capcom_id = to_str(unpacker.lp2_string())
  1048. search_info = unpacker.UserSearchInfo()
  1049. self.server.debug("SearchInfo: {}, {!r}".format(capcom_id,
  1050. search_info))
  1051. self.sendAnsUserSearchInfo(capcom_id, search_info, seq)
  1052. def sendAnsUserSearchInfo(self, capcom_id, search_info, seq):
  1053. """AnsUserSearchInfo packet.
  1054. ID: 66360200
  1055. JP: ユーザ検索データ返答
  1056. TR: User search data response
  1057. """
  1058. user = self.session.find_user_by_capcom_id(capcom_id)
  1059. if not user:
  1060. # TODO: Find a better way to notify offline status in friend list
  1061. user_info = pati.UserSearchInfo()
  1062. user_info.capcom_id = pati.String(capcom_id)
  1063. user_info.hunter_name = pati.String("OFFLINE")
  1064. data = user_info.pack() + pati.pack_optional_fields([])
  1065. self.sendAnsAlert(PatID4.AnsUserSearchInfo, data, seq)
  1066. return
  1067. user_info = pati.UserSearchInfo()
  1068. user_info.capcom_id = pati.String(user.capcom_id)
  1069. user_info.hunter_name = pati.String(user.hunter_name)
  1070. user_info.stats = pati.Binary(user.hunter_info.pack())
  1071. user_info.layer_host = pati.Binary(user.get_layer_host_data())
  1072. user_info.unk_byte_0x07 = pati.Byte(1)
  1073. user_info.server_name = pati.String("\t".join([
  1074. user.local_info["server_name"] or "",
  1075. user.local_info["gate_name"] or "",
  1076. user.local_info["city_name"] or ""
  1077. ]))
  1078. user_info.unk_byte_0x0b = pati.Byte(1)
  1079. user_info.unk_string_0x0c = pati.String("StrC")
  1080. user_info.city_capacity = pati.Long(4)
  1081. user_info.city_size = pati.Long(3)
  1082. # This fields are used to identify a user.
  1083. # Specifically when a client is deserializing data from the packets
  1084. # `NtcLayerBinary` and `NtcLayerBinary2`
  1085. # TODO: Proper field value and name
  1086. user_info.info_mine_0x0f = pati.Long(int(hash(user.capcom_id))
  1087. & 0xffffffff)
  1088. user_info.info_mine_0x10 = pati.Long(int(hash(user.capcom_id[::-1]))
  1089. & 0xffffffff)
  1090. data = user_info.pack()
  1091. # TODO: Figure out the optional fields
  1092. data += pati.pack_optional_fields([])
  1093. self.send_packet(PatID4.AnsUserSearchInfo, data, seq)
  1094. def recvReqLayerStart(self, packet_id, data, seq):
  1095. """ReqLayerStart packet.
  1096. ID: 64010100
  1097. JP: レイヤ開始要求
  1098. TR: Layer start request
  1099. """
  1100. unk1 = pati.unpack_bytes(data)
  1101. unk2 = pati.unpack_bytes(data, len(unk1) + 1)
  1102. self.sendAnsLayerStart(unk1, unk2, seq)
  1103. def sendAnsLayerStart(self, unk1, unk2, seq):
  1104. """AnsLayerStart packet.
  1105. ID: 64010200
  1106. JP: レイヤ開始応答
  1107. TR: Layer start response
  1108. """
  1109. layer = self.session.layer_start()
  1110. self.send_packet(PatID4.AnsLayerStart, layer.pack(), seq)
  1111. def sendNtcCircleLeave(self, circle, circle_index, seq):
  1112. """NtcCircleLeave packet.
  1113. ID: 65041000
  1114. JP: サークルアウト通知
  1115. TR: Circle out notification
  1116. """
  1117. player_index = circle.players.index(self.session) + 1
  1118. data = struct.pack(">I", circle_index)
  1119. data += pati.lp2_string(self.session.capcom_id)
  1120. data += struct.pack(">B", player_index)
  1121. unk01 = 0x00 # Flag of some sort
  1122. data += struct.pack(">B", unk01)
  1123. self.server.circle_broadcast(circle, PatID4.NtcCircleLeave, data, seq,
  1124. self.session)
  1125. def recvReqCircleInfoNoticeSet(self, packet_id, data, seq):
  1126. """ReqCircleInfoNoticeSet packet.
  1127. ID: 65800100
  1128. JP: サークル通知定義登録要求
  1129. TR: Circle notification subscription request
  1130. """
  1131. unk1 = pati.unpack_bytes(data)
  1132. unk2 = pati.unpack_bytes(data, len(unk1) + 1)
  1133. self.sendAnsCircleInfoNoticeSet(unk1, unk2, seq)
  1134. def sendAnsCircleInfoNoticeSet(self, unk1, unk2, seq):
  1135. """AnsCircleInfoNoticeSet packet.
  1136. ID: 65800200
  1137. JP: サークル通知定義登録返答
  1138. TR: Circle notification subscription response
  1139. """
  1140. self.send_packet(PatID4.AnsCircleInfoNoticeSet, b"", seq)
  1141. def recvNtcCheatCheck(self, packet_id, data, seq):
  1142. """NtcCheatCheck packet.
  1143. ID: 60801000
  1144. JP: チートチェックデータ送信
  1145. TR: Send cheat check data
  1146. TODO: Handle cheat check data.
  1147. """
  1148. pass
  1149. def recvReqUserSearchSet(self, packet_id, data, seq):
  1150. """ReqUserSearchSet packet.
  1151. ID: 66300100
  1152. JP: ユーザ検索設定要求
  1153. TR: User search settings request
  1154. """
  1155. extra = pati.unpack_optional_fields(data)
  1156. self.server.debug("UserSearchSet: {!r}".format(extra))
  1157. self.sendAnsUserSearchSet(extra, seq)
  1158. def sendAnsUserSearchSet(self, extra, seq):
  1159. """AnsUserSearchSet packet.
  1160. ID: 66300200
  1161. JP: ユーザ検索設定返答
  1162. TR: User search settings response
  1163. """
  1164. self.send_packet(PatID4.AnsUserSearchSet, b"", seq)
  1165. def recvReqBinaryVersion(self, packet_id, data, seq):
  1166. """ReqBinaryVersion packet.
  1167. ID: 63010100
  1168. JP: バイナリバージョン確認
  1169. TR: Binary version check
  1170. """
  1171. binary_type, = struct.unpack(">B", data)
  1172. self.sendAnsBinaryVersion(binary_type, seq)
  1173. def sendAnsBinaryVersion(self, binary_type, seq):
  1174. """AnsBinaryVersion packet.
  1175. ID: 63010200
  1176. JP: バイナリバージョン確認応答
  1177. TR: Binary version acknowledgment
  1178. """
  1179. unused = 0
  1180. binary = PAT_BINARIES[binary_type]
  1181. version = binary["version"]
  1182. if callable(version):
  1183. version = version(self.server.binary_loader)
  1184. data = struct.pack(">BI", unused, version)
  1185. self.send_packet(PatID4.AnsBinaryVersion, data, seq)
  1186. def recvReqLayerUserListHead(self, packet_id, data, seq):
  1187. """ReqLayerUserListHead packet.
  1188. ID: 64640100
  1189. JP: レイヤユーザリスト数要求
  1190. TR: Layer user list count request
  1191. """
  1192. with pati.Unpacker(data) as unpacker:
  1193. unk, = unpacker.struct(">B")
  1194. layer = unpacker.lp2_string()
  1195. first_index, count = unpacker.struct(">II")
  1196. fields = unpacker.bytes()
  1197. self.server.debug("LayerUserListHead({}, {!r}, {}, {}, {!r}".format(
  1198. unk, layer, first_index, count, fields))
  1199. self.sendAnsLayerUserListHead(unk, layer, first_index, count, fields,
  1200. seq)
  1201. def sendAnsLayerUserListHead(self, unk, layer, first_index, count,
  1202. fields,
  1203. seq):
  1204. """AnsLayerUserListHead packet.
  1205. ID: 64640200
  1206. JP: レイヤユーザリスト数返答
  1207. TR: Layer user list count response
  1208. """
  1209. depth, server_id, unk_id, gate_id, city_id = struct.unpack_from(
  1210. ">IIHHH", layer)
  1211. self.search_data = self.session.find_users_by_layer(
  1212. server_id, gate_id, city_id, first_index, count)
  1213. data = struct.pack(">II", first_index, len(self.search_data))
  1214. self.send_packet(PatID4.AnsLayerUserListHead, data, seq)
  1215. def recvReqLayerUserListData(self, packet_id, data, seq):
  1216. """ReqLayerUserListData packet.
  1217. ID: 64650100
  1218. JP: レイヤユーザリスト要求
  1219. TR: Layer user list request
  1220. """
  1221. first_index, count = struct.unpack(">II", data)
  1222. self.sendAnsLayerUserListData(first_index, count, seq)
  1223. def sendAnsLayerUserListData(self, first_index, count, seq):
  1224. """AnsLayerUserListData packet.
  1225. ID: 64650200
  1226. JP: レイヤユーザリスト返答
  1227. TR: Layer user list response
  1228. """
  1229. unk = 1
  1230. users = self.search_data
  1231. data = struct.pack(">II", unk, len(users))
  1232. for _, user in users:
  1233. layer_user = pati.LayerUserInfo()
  1234. layer_user.capcom_id = pati.String(user.capcom_id)
  1235. layer_user.hunter_name = pati.String(user.hunter_name)
  1236. layer_user.layer_host = pati.Binary(user.get_layer_host_data())
  1237. data += layer_user.pack()
  1238. data += pati.pack_optional_fields(user.get_optional_fields())
  1239. self.send_packet(PatID4.AnsLayerUserListData, data, seq)
  1240. def recvReqLayerUserListFoot(self, packet_id, data, seq):
  1241. """ReqLayerUserListFoot packet.
  1242. ID: 64660100
  1243. JP: レイヤユーザリスト終了要求
  1244. TR: Layer user list end of transmission request
  1245. """
  1246. self.sendAnsLayerUserListFoot(seq)
  1247. def sendAnsLayerUserListFoot(self, seq):
  1248. """AnsLayerUserListFoot packet.
  1249. ID: 64660200
  1250. JP: レイヤユーザリスト終了返答
  1251. TR: Layer user list end of transmission response
  1252. """
  1253. data = b""
  1254. self.send_packet(PatID4.AnsLayerUserListFoot, data, seq)
  1255. def recvReqLayerUserSearchHead(self, packet_id, data, seq):
  1256. """ReqLayerUserSearchHead packet.
  1257. ID: 64670100
  1258. JP: レイヤユーザ検索リスト数要求
  1259. TR: Layer user search list count request
  1260. Sent by the game when searching for players at the gate:
  1261. - Online > Player Search > Gate Search
  1262. """
  1263. with pati.Unpacker(data) as unpacker:
  1264. self.search_info = {
  1265. "unk": unpacker.struct(">B")[0],
  1266. "layer": unpacker.lp2_string(),
  1267. "capcom_id": to_str(unpacker.lp2_string()),
  1268. "hunter_name": unpacker.lp2_string(),
  1269. "search": unpacker.detailed_optional_fields(),
  1270. "offset": unpacker.struct(">I")[0],
  1271. "limit": unpacker.struct(">I")[0],
  1272. "fields": unpacker.bytes()
  1273. }
  1274. self.server.debug((
  1275. "ReqLayerUserSearchHead("
  1276. "unk={unk}, layer={layer!r}, "
  1277. "capcom_id={capcom_id!r}, hunter_name={hunter_name!r}, "
  1278. "search={search!r}, offset={offset}, limit={limit}, "
  1279. "fields={fields!r})"
  1280. ).format(**self.search_info))
  1281. self.sendAnsLayerUserSearchHead(seq)
  1282. def sendAnsLayerUserSearchHead(self, seq):
  1283. """AnsLayerUserSearchHead packet.
  1284. ID: 64670200
  1285. JP: レイヤユーザ検索リスト数返答
  1286. TR: Layer user search list count response
  1287. """
  1288. depth, server_id, unk_id, gate_id, city_id = struct.unpack_from(
  1289. ">IIHHH", self.search_info["layer"]
  1290. )
  1291. self.search_data = self.session.find_users_by_layer(
  1292. server_id, gate_id, city_id,
  1293. self.search_info["offset"], self.search_info["limit"],
  1294. recursive=True
  1295. )
  1296. unk = 0
  1297. data = struct.pack(">II", unk, len(self.search_data))
  1298. self.send_packet(PatID4.AnsLayerUserSearchHead, data, seq)
  1299. def recvReqLayerUserSearchData(self, packet_id, data, seq):
  1300. """ReqLayerUserSearchData packet.
  1301. ID: 64680100
  1302. JP: レイヤユーザ検索リスト要求
  1303. TR: Layer user search list request
  1304. """
  1305. offset, size = struct.unpack(">II", data)
  1306. self.sendAnsLayerUserSearchData(offset, size, seq)
  1307. def sendAnsLayerUserSearchData(self, offset, size, seq):
  1308. """AnsLayerUserSearchData packet.
  1309. ID: 64680200
  1310. JP: レイヤユーザ検索リスト返答
  1311. TR: Layer user search list response
  1312. """
  1313. unk = 0
  1314. layer_users = self.search_data
  1315. count = len(layer_users)
  1316. data = struct.pack(">II", unk, count)
  1317. for _, user in layer_users:
  1318. layer_user = pati.LayerUserInfo()
  1319. layer_user.capcom_id = pati.String(user.capcom_id)
  1320. layer_user.hunter_name = pati.String(user.hunter_name)
  1321. layer_user.layer_host = pati.Binary(user.get_layer_host_data())
  1322. layer_user.assert_fields(self.search_info["fields"])
  1323. data += layer_user.pack()
  1324. data += pati.pack_optional_fields(user.get_optional_fields())
  1325. self.send_packet(PatID4.AnsLayerUserSearchData, data, seq)
  1326. def recvReqLayerUserSearchFoot(self, packet_id, data, seq):
  1327. """ReqLayerUserSearchFoot packet.
  1328. ID: 64690100
  1329. JP: レイヤユーザ検索リスト終了要求
  1330. TR: Layer user search list end of transmission request
  1331. """
  1332. self.sendAnsLayerUserSearchFoot(seq)
  1333. def sendAnsLayerUserSearchFoot(self, seq):
  1334. """AnsLayerUserSearchFoot packet.
  1335. ID: 64690200
  1336. JP: レイヤユーザ検索リスト終了返答
  1337. TR: Layer user search list end of transmission response
  1338. """
  1339. self.send_packet(PatID4.AnsLayerUserSearchFoot, b"", seq)
  1340. def recvReqFriendList(self, packet_id, data, seq):
  1341. """ReqFriendList packet.
  1342. ID: 66540100
  1343. JP: フレンドリスト要求
  1344. TR: Friend list request
  1345. """
  1346. with pati.Unpacker(data) as unpacker:
  1347. first_index, count = unpacker.struct(">II")
  1348. fields = unpacker.bytes()
  1349. self.sendAnsFriendList(first_index, count, fields, seq)
  1350. def sendAnsFriendList(self, first_index, count, fields, seq):
  1351. """AnsFriendList packet.
  1352. ID: 66540200
  1353. JP: フレンドリスト返答
  1354. TR: Friend list response
  1355. """
  1356. unk = 0
  1357. friends = self.session.get_friends(first_index, count)
  1358. count = len(friends)
  1359. data = struct.pack(">II", unk, count)
  1360. for index, (capcom_id, hunter_name) in enumerate(friends, 1):
  1361. friend = pati.FriendData()
  1362. friend.index = pati.Long(index)
  1363. friend.capcom_id = pati.String(capcom_id)
  1364. friend.hunter_name = pati.String(hunter_name)
  1365. friend.assert_fields(fields)
  1366. data += friend.pack()
  1367. self.send_packet(PatID4.AnsFriendList, data, seq)
  1368. def recvReqBlackAdd(self, packet_id, data, seq):
  1369. """ReqBlackAdd packet.
  1370. ID: 66600100
  1371. JP: ブラックデータ登録要求
  1372. TR: Black data registration request
  1373. TODO: Implement it properly
  1374. """
  1375. with pati.Unpacker(data) as unpacker:
  1376. capcom_id = to_str(unpacker.lp2_string())
  1377. black_data = unpacker.BlackListUserData()
  1378. self.sendAnsBlackAdd(capcom_id, black_data, seq)
  1379. def sendAnsBlackAdd(self, capcom_id, black_data, seq):
  1380. """AnsBlackAdd packet.
  1381. ID: 66600200
  1382. JP: ブラックデータ登録返答
  1383. TR: Black data registration response
  1384. """
  1385. self.send_packet(PatID4.AnsBlackAdd, b"", seq)
  1386. def recvReqBlackDelete(self, packet_id, data, seq):
  1387. """ReqBlackDelete packet.
  1388. ID: 66610100
  1389. JP: ブラックデータ削除要求
  1390. TR: Black data deletion request
  1391. """
  1392. capcom_id = to_str(pati.unpack_lp2_string(data))
  1393. self.sendAnsBlackDelete(capcom_id, seq)
  1394. def sendAnsBlackDelete(self, capcom_id, seq):
  1395. """AnsBlackDelete packet.
  1396. ID: 66610200
  1397. JP: ブラックデータ削除返答
  1398. TR: Black data deletion response
  1399. """
  1400. self.send_packet(PatID4.AnsBlackDelete, b"", seq)
  1401. def recvReqBlackList(self, packet_id, data, seq):
  1402. """ReqBlackList packet.
  1403. ID: 66620100
  1404. JP: ブラックリスト要求
  1405. TR: Blacklist request
  1406. TODO: Implement it properly
  1407. """
  1408. unk1, unk2 = struct.unpack_from(">II", data) # 1st/last index?
  1409. unk3 = data[8:] # PAT fields filter? (1,2,3)?
  1410. self.sendAnsBlackList(unk1, unk2, unk3, seq)
  1411. def sendAnsBlackList(self, unk1, unk2, unk3, seq):
  1412. """AnsBlackList packet.
  1413. ID: 66620200
  1414. JP: ブラックリスト返答
  1415. TR: Blacklist response
  1416. """
  1417. dummy = pati.BlackListUserData()
  1418. dummy.index = pati.Long(0)
  1419. dummy.capcom_id = pati.String("")
  1420. dummy.hunter_name = pati.String("")
  1421. blacklisted_users = [dummy]
  1422. unk = 0
  1423. count = len(blacklisted_users)
  1424. data = struct.pack(">II", unk, count)
  1425. data += b"".join([item.pack() for item in blacklisted_users])
  1426. self.send_packet(PatID4.AnsBlackList, data, seq)
  1427. def recvNtcLayerChat(self, packet_id, data, seq):
  1428. """NtcLayerChat packet.
  1429. ID: 64721000
  1430. JP: レイヤチャット通知
  1431. TR: Layer chat notification
  1432. The game sends a chat message to relay.
  1433. NB: The message won't be displayed if the Capcom ID is blank.
  1434. """
  1435. with pati.Unpacker(data) as unpacker:
  1436. unk1, = unpacker.struct(">B")
  1437. info = unpacker.MessageInfo()
  1438. message = unpacker.lp2_string()
  1439. self.server.debug("NtcLayerChat: {}, {!r}, {}".format(
  1440. unk1, info, message))
  1441. self.sendNtcLayerChat(unk1, info, message, seq)
  1442. def sendNtcLayerChat(self, unk1, info, message, seq):
  1443. """NtcLayerChat packet.
  1444. ID: 64721000
  1445. JP: レイヤチャット送信
  1446. TR: Layer chat transmission
  1447. NB: Request and response share the same packet ID
  1448. The server sends a chat message.
  1449. """
  1450. data = struct.pack(">B", unk1)
  1451. info.text_color = pati.Long(LAYER_CHAT_COLORS[self.session.layer])
  1452. info.sender_id = pati.String(self.session.capcom_id)
  1453. info.sender_name = pati.String(self.session.hunter_name)
  1454. data += info.pack()
  1455. data += pati.lp2_string(message)
  1456. self.server.layer_broadcast(self.session, PatID4.NtcLayerChat, data,
  1457. seq)
  1458. def recvReqLayerTell(self, packet_id, data, seq):
  1459. """ReqLayerTell packet.
  1460. ID: 64730100
  1461. JP: レイヤ相手指定チャット送信
  1462. TR: Layer specified chat transmission
  1463. """
  1464. with pati.Unpacker(data) as unpacker:
  1465. recipient_id = to_str(unpacker.lp2_string())
  1466. info = unpacker.MessageInfo()
  1467. message = unpacker.lp2_string()
  1468. self.server.debug("ReqTell: {}, {!r}, {}".format(
  1469. recipient_id, info, message))
  1470. self.sendAnsLayerTell(recipient_id, info, message, seq)
  1471. def sendAnsLayerTell(self, recipient_id, info, message, seq):
  1472. """AnsLayerTell packet.
  1473. ID: 64730200
  1474. JP: レイヤ相手指定チャット返信
  1475. TR: Layer partner specified chat reply
  1476. """
  1477. self.send_packet(PatID4.AnsLayerTell, b"", seq)
  1478. self.sendNtcLayerTell(recipient_id, info, message, seq)
  1479. def sendNtcLayerTell(self, recipient_id, info, message, seq):
  1480. """NtcLayerTell packet.
  1481. ID: 64731000
  1482. JP: レイヤ相手指定チャット通知
  1483. TR: Layer partner specified chat notification
  1484. """
  1485. data = pati.lp2_string(recipient_id)
  1486. info.unk_long_0x02 = pati.Long(20)
  1487. info.sender_id = pati.String(self.session.capcom_id)
  1488. info.sender_name = pati.String(self.session.hunter_name)
  1489. data += info.pack()
  1490. data += pati.lp2_string(message)
  1491. self.send_packet(PatID4.NtcLayerTell, data, seq)
  1492. for _, player in self.session.get_layer_players():
  1493. if player.capcom_id == recipient_id:
  1494. handler = self.server.get_pat_handler(player)
  1495. if handler:
  1496. handler.try_send_packet(PatID4.NtcLayerTell, data, seq)
  1497. def recvNtcCircleChat(self, packet_id, data, seq):
  1498. """NtcCircleChat packet.
  1499. ID: 65721000
  1500. JP: サークルチャット通知
  1501. TR: Circle chat notification
  1502. """
  1503. with pati.Unpacker(data) as unpacker:
  1504. info = unpacker.MessageInfo()
  1505. message = unpacker.lp2_string()
  1506. self.server.debug("NtcCircleChat: {!r}, {}".format(
  1507. info, message))
  1508. self.sendNtcCircleChat(info, message, seq)
  1509. def sendNtcCircleChat(self, info, message, seq):
  1510. """NtcCircleChat packet.
  1511. ID: 65721000
  1512. JP: サークルチャット送信
  1513. TR: Circle chat transmission
  1514. """
  1515. info.sender_id = pati.String(self.session.capcom_id)
  1516. info.sender_name = pati.String(self.session.hunter_name)
  1517. data = info.pack()
  1518. data += pati.lp2_string(message)
  1519. circle = self.session.get_circle()
  1520. self.server.circle_broadcast(circle, PatID4.NtcCircleChat, data,
  1521. seq, self.session)
  1522. def recvReqTell(self, packet_id, data, seq):
  1523. """ReqTell packet.
  1524. ID: 66110100
  1525. JP: 相手指定チャット送信
  1526. TR: Send partner message
  1527. """
  1528. with pati.Unpacker(data) as unpacker:
  1529. recipient_id = to_str(unpacker.lp2_string())
  1530. info = unpacker.MessageInfo()
  1531. message = unpacker.lp2_string()
  1532. self.server.debug("ReqTell: {}, {!r}, {}".format(
  1533. recipient_id, info, message))
  1534. self.sendAnsTell(recipient_id, info, message, seq)
  1535. def sendAnsTell(self, recipient_id, info, message, seq):
  1536. """AnsTell packet.
  1537. ID: 66110200
  1538. JP: 相手指定チャット返信
  1539. TR: Receive partner message
  1540. """
  1541. self.send_packet(PatID4.AnsTell, b"", seq)
  1542. self.sendNtcTell(recipient_id, info, message, seq)
  1543. def sendNtcTell(self, recipient_id, info, message, seq):
  1544. """NtcTell packet.
  1545. ID: 66111000
  1546. JP: 相手指定チャット通知
  1547. TR: Partner message notification
  1548. """
  1549. data = b""
  1550. data += pati.lp2_string(recipient_id)
  1551. info.unk_long_0x02 = pati.Long(20)
  1552. info.sender_id = pati.String(self.session.capcom_id)
  1553. info.sender_name = pati.String(self.session.hunter_name)
  1554. data += info.pack()
  1555. data += pati.lp2_string(message)
  1556. self.try_send_packet_to(recipient_id, PatID4.NtcTell, data, seq)
  1557. def recvReqFriendAdd(self, packet_id, data, seq):
  1558. """ReqFriendAdd packet.
  1559. ID: 66500100
  1560. JP: フレンド登録要求
  1561. TR: Friend registration request
  1562. TODO: Merge this with ReqTell?
  1563. """
  1564. with pati.Unpacker(data) as unpacker:
  1565. recipient_id = to_str(unpacker.lp2_string())
  1566. info = unpacker.MessageInfo()
  1567. message = unpacker.lp2_string()
  1568. self.server.debug("ReqFriendAdd: {}, {!r}, {}".format(
  1569. recipient_id, info, message))
  1570. self.sendAnsFriendAdd(recipient_id, info, message, seq)
  1571. def sendAnsFriendAdd(self, recipient_id, info, message, seq):
  1572. """AnsFriendAdd packet.
  1573. ID: 66500200
  1574. JP: フレンド登録返答
  1575. TR: Friend registration response
  1576. """
  1577. if not self.session.add_friend_request(recipient_id):
  1578. self.sendAnsAlert(PatID4.AnsFriendAdd,
  1579. "<LF=8><BODY><CENTER>Unknown Capcom ID.<END>",
  1580. seq)
  1581. return
  1582. self.send_packet(PatID4.AnsFriendAdd, b"", seq)
  1583. self.sendNtcFriendAccept(recipient_id, info, message, seq)
  1584. def sendNtcFriendAdd(self, recipient_id, accepted, seq):
  1585. """NtcFriendAdd packet.
  1586. ID: 66501000
  1587. JP: フレンド登録完了通知
  1588. TR: Friend registration completed notification
  1589. """
  1590. if not accepted:
  1591. return
  1592. # Send notification to friend
  1593. data = b""
  1594. data += pati.lp2_string(recipient_id)
  1595. friend = pati.FriendData()
  1596. friend.index = pati.Long(1) # TODO: Reverse-engineer this field
  1597. friend.capcom_id = pati.String(self.session.capcom_id)
  1598. friend.hunter_name = pati.String(self.session.hunter_name)
  1599. data += friend.pack()
  1600. data += struct.pack(">B", accepted)
  1601. self.try_send_packet_to(recipient_id, PatID4.NtcFriendAdd, data, seq)
  1602. # Send notification to self
  1603. data = pati.lp2_string(self.session.capcom_id)
  1604. friend = pati.FriendData()
  1605. friend.index = pati.Long(1) # TODO: Reverse-engineer this field
  1606. friend.capcom_id = pati.String(recipient_id)
  1607. friend.hunter_name = pati.String(
  1608. self.session.get_user_name(recipient_id))
  1609. data += friend.pack()
  1610. data += struct.pack(">B", accepted)
  1611. self.send_packet(PatID4.NtcFriendAdd, data, seq)
  1612. def recvReqFriendAccept(self, packet_id, data, seq):
  1613. """ReqFriendAccept packet.
  1614. ID: 66510100
  1615. JP: フレンド登録依頼返答要求
  1616. TR: Friend registration accept request
  1617. """
  1618. with pati.Unpacker(data) as unpacker:
  1619. recipient_id = to_str(unpacker.lp2_string())
  1620. accepted, = unpacker.struct(">B")
  1621. self.sendAnsFriendAccept(recipient_id, accepted, seq)
  1622. self.sendNtcFriendAdd(recipient_id, accepted, seq)
  1623. def sendAnsFriendAccept(self, recipient_id, accepted, seq):
  1624. """AnsFriendAccept packet.
  1625. ID: 66510200
  1626. JP: フレンド登録依頼返答返答
  1627. TR: Friend registration accept response
  1628. """
  1629. self.session.accept_friend(recipient_id, accepted)
  1630. self.send_packet(PatID4.AnsFriendAccept, b"", seq)
  1631. def sendNtcFriendAccept(self, recipient_id, info, message, seq):
  1632. """NtcFriendAccept packet.
  1633. ID: 66511000
  1634. JP: フレンド登録依頼通知
  1635. TR: Friend registration request notification
  1636. TODO: Merge this with NtcTell?
  1637. """
  1638. data = b""
  1639. data += pati.lp2_string(recipient_id)
  1640. info.unk_long_0x02 = pati.Long(20)
  1641. info.sender_id = pati.String(self.session.capcom_id)
  1642. info.sender_name = pati.String(self.session.hunter_name)
  1643. data += info.pack()
  1644. data += pati.lp2_string(message)
  1645. self.try_send_packet_to(recipient_id, PatID4.NtcFriendAccept, data,
  1646. seq)
  1647. def recvReqFriendDelete(self, packet_id, data, seq):
  1648. """ReqFriendDelete packet.
  1649. ID: 66530100
  1650. JP: フレンドデータ削除要求
  1651. TR: Friend data deletion request
  1652. """
  1653. capcom_id = to_str(pati.unpack_lp2_string(data))
  1654. self.sendAnsFriendDelete(capcom_id, seq)
  1655. def sendAnsFriendDelete(self, capcom_id, seq):
  1656. """AnsFriendDelete packet.
  1657. ID: 66530200
  1658. JP: フレンドデータ削除返答
  1659. TR: Friend data deletion response
  1660. """
  1661. self.session.delete_friend(capcom_id)
  1662. self.send_packet(PatID4.AnsFriendDelete, b"", seq)
  1663. def recvReqLayerChildListHead(self, packet_id, data, seq):
  1664. """ReqLayerChildListHead packet.
  1665. ID: 64240100
  1666. JP: 子レイヤリスト数要求
  1667. TR: Child layer list count request
  1668. """
  1669. unk1, unk2 = struct.unpack_from(">II", data) # 1st/last index?
  1670. layer_info = data[8:8+0xf]
  1671. self.sendAnsLayerChildListHead(unk1, unk2, layer_info, seq)
  1672. def sendAnsLayerChildListHead(self, unk1, unk2, layer_info, seq):
  1673. """AnsLayerChildListHead packet.
  1674. ID: 64240200
  1675. JP: 子レイヤリスト数返答
  1676. TR: Child layer list count response
  1677. """
  1678. unk = 0
  1679. count = len(self.session.get_layer_children())
  1680. data = struct.pack(">II", unk, count)
  1681. self.send_packet(PatID4.AnsLayerChildListHead, data, seq)
  1682. def recvReqLayerChildListData(self, packet_id, data, seq):
  1683. """ReqLayerChildListData packet.
  1684. ID: 64250100
  1685. JP: 子レイヤリスト要求
  1686. TR: Child layer list request
  1687. """
  1688. first_index, count = struct.unpack_from(">II", data)
  1689. self.sendAnsLayerChildListData(first_index, count, seq)
  1690. def sendAnsLayerChildListData(self, first_index, count, seq):
  1691. """AnsLayerChildListData packet.
  1692. ID: 64250200
  1693. JP: 子レイヤリスト返答
  1694. TR: Child layer list response
  1695. """
  1696. unk = first_index
  1697. data = struct.pack(">II", unk, count)
  1698. data += pati.get_layer_children(self.session, first_index, count)
  1699. self.send_packet(PatID4.AnsLayerChildListData, data, seq)
  1700. def recvReqLayerChildListFoot(self, packet_id, data, seq):
  1701. """ReqLayerChildListFoot packet.
  1702. ID: 64260100
  1703. JP: 子レイヤリスト終了要求
  1704. TR: Child layer list end of transmission request
  1705. """
  1706. self.sendAnsLayerChildListFoot(seq)
  1707. def sendAnsLayerChildListFoot(self, seq):
  1708. """AnsLayerChildListFoot packet.
  1709. ID: 64260200
  1710. JP: 子レイヤリスト終了返答
  1711. TR: Child layer list end of transmission response
  1712. """
  1713. self.send_packet(PatID4.AnsLayerChildListFoot, b"", seq)
  1714. def recvReqLayerSiblingListHead(self, packet_id, data, seq):
  1715. """ReqLayerSiblingListHead packet.
  1716. ID: 64270100
  1717. JP: 兄弟レイヤリスト数要求
  1718. TR: Layer sibling list count request
  1719. Sent by the game when leaving the gate via the entrance:
  1720. - Relocate > Change Gates
  1721. TODO: Merge this with ReqLayerChildListHead?
  1722. """
  1723. unk1, unk2 = struct.unpack_from(">II", data) # 1st/last index?
  1724. layer_info = data[8:8+0xf]
  1725. self.sendAnsLayerSiblingListHead(unk1, unk2, layer_info, seq)
  1726. def sendAnsLayerSiblingListHead(self, unk1, unk2, layer_info, seq):
  1727. """AnsLayerSiblingListHead packet.
  1728. ID: 64270200
  1729. JP: 兄弟レイヤリスト数返答
  1730. TR: Layer sibling list count response
  1731. TODO: Merge this with AnsLayerChildListHead?
  1732. """
  1733. unk = 0
  1734. count = len(self.session.get_layer_sibling())
  1735. data = struct.pack(">II", unk, count)
  1736. self.send_packet(PatID4.AnsLayerSiblingListHead, data, seq)
  1737. def recvReqLayerSiblingListData(self, packet_id, data, seq):
  1738. """ReqLayerSiblingListData packet.
  1739. ID: 64280100
  1740. JP: 兄弟レイヤリスト要求
  1741. TR: Layer sibling list request
  1742. TODO: Merge this with ReqLayerChildListData?
  1743. """
  1744. first_index, count = struct.unpack_from(">II", data)
  1745. self.sendAnsLayerSiblingListData(first_index, count, seq)
  1746. def sendAnsLayerSiblingListData(self, first_index, count, seq):
  1747. """AnsLayerSiblingListData packet.
  1748. ID: 64280200
  1749. JP: 兄弟レイヤリスト返答
  1750. TR: Layer sibling list response
  1751. TODO: Merge this with AnsLayerChildListData?
  1752. """
  1753. unk = first_index
  1754. data = struct.pack(">II", unk, count)
  1755. data += pati.get_layer_sibling(self.session, first_index, count)
  1756. self.send_packet(PatID4.AnsLayerSiblingListData, data, seq)
  1757. def recvReqLayerSiblingListFoot(self, packet_id, data, seq):
  1758. """ReqLayerSiblingListFoot packet.
  1759. ID: 64290100
  1760. JP: 兄弟レイヤリスト終了要求
  1761. TR: Layer sibling list end of transmission request
  1762. """
  1763. self.sendAnsLayerSiblingListFoot(seq)
  1764. def sendAnsLayerSiblingListFoot(self, seq):
  1765. """AnsLayerSiblingListFoot packet.
  1766. ID: 64290200
  1767. JP: 兄弟レイヤリスト終了返答
  1768. TR: Layer sibling list end of transmission response
  1769. """
  1770. self.send_packet(PatID4.AnsLayerSiblingListFoot, b"", seq)
  1771. def recvReqLayerChildInfo(self, packet_id, data, seq):
  1772. """ReqLayerChildInfo packet.
  1773. ID: 64230100
  1774. JP: 子レイヤ情報要求
  1775. TR: Child layer information request
  1776. """
  1777. unk1, = struct.unpack_from(">H", data)
  1778. layer_data = data[2:] # layer_data with some unknown ones appended
  1779. self.sendAnsLayerChildInfo(unk1, layer_data, seq)
  1780. def sendAnsLayerChildInfo(self, unk1, layer_data, seq):
  1781. """AnsLayerChildInfo packet.
  1782. ID: 64230200
  1783. JP: 子レイヤ情報返答
  1784. TR: Child layer information response
  1785. """
  1786. data = struct.pack(">H", 1)
  1787. data += pati.getDummyLayerData().pack()
  1788. data += b"\0" * 2
  1789. self.send_packet(PatID4.AnsLayerChildInfo, data, seq)
  1790. def recvReqLayerDown(self, packet_id, data, seq):
  1791. """ReqLayerDown packet.
  1792. ID: 64140100
  1793. JP: レイヤダウン要求(番号指定)
  1794. TR: Layer down request (number specified)
  1795. """
  1796. layer_id, = struct.unpack_from(">H", data) # WordInc
  1797. layer_set = data[2:] # TODO parse LayerSet
  1798. self.sendAnsLayerDown(layer_id, layer_set, seq)
  1799. def sendAnsLayerDown(self, layer_id, layer_set, seq):
  1800. """AnsLayerDown packet.
  1801. ID: 64140200
  1802. JP: レイヤダウン返答
  1803. TR: Layer down response
  1804. """
  1805. data = struct.pack(">H", layer_id)
  1806. self.session.layer_down(layer_id)
  1807. self.send_packet(PatID4.AnsLayerDown, data, seq)
  1808. def recvReqUserStatusSet(self, packet_id, data, seq):
  1809. """ReqUserStatusSet packet.
  1810. ID: 66400100
  1811. JP: ユーザステータス設定要求
  1812. TR: User status settings request
  1813. """
  1814. status_set = pati.UserStatusSet.unpack(data)
  1815. self.server.debug("UserStatusSet: {!r}".format(status_set))
  1816. self.sendAnsUserStatusSet(status_set, seq)
  1817. def sendAnsUserStatusSet(self, status_set, seq):
  1818. """AnsUserStatusSet packet.
  1819. ID: 66400200
  1820. JP: ユーザステータス設定返答
  1821. TR: User status settings response
  1822. """
  1823. self.send_packet(PatID4.AnsUserStatusSet, b"", seq)
  1824. def recvReqUserBinaryNotice(self, packet_id, data, seq):
  1825. """ReqUserBinaryNotice packet.
  1826. ID: 66320100
  1827. JP: ユーザ表示用バイナリ通知要求
  1828. TR: User display binary notification request
  1829. """
  1830. with pati.Unpacker(data) as unpacker:
  1831. unk1, = unpacker.struct(">B")
  1832. capcom_id = to_str(unpacker.lp2_string())
  1833. offset, length = unpacker.struct(">II")
  1834. self.sendAnsUserBinaryNotice(unk1, capcom_id, offset, length, seq)
  1835. def sendAnsUserBinaryNotice(self, unk1, capcom_id, offset, length, seq):
  1836. """AnsUserBinaryNotice packet.
  1837. ID: 66320200
  1838. JP: ユーザ表示用バイナリ通知返答
  1839. TR: User display binary notification response
  1840. """
  1841. self.sendNtcUserBinaryNotice(unk1, capcom_id, offset, length, seq)
  1842. self.send_packet(PatID4.AnsUserBinaryNotice, b"", seq)
  1843. def sendNtcUserBinaryNotice(self, unk1, capcom_id, offset, length, seq):
  1844. """NtcUserBinaryNotice packet.
  1845. ID: 66321000
  1846. JP: ユーザ表示用バイナリ通知通知
  1847. TR: User display binary notification notice
  1848. """
  1849. data = struct.pack(">B", unk1)
  1850. data += pati.lp2_string(self.session.capcom_id)
  1851. data += struct.pack(">I", offset)
  1852. data += pati.lp2_string(self.session.hunter_info.pack()[offset:
  1853. offset+length])
  1854. self.server.layer_broadcast(self.session, PatID4.NtcUserBinaryNotice,
  1855. data, seq)
  1856. def recvReqLayerDetailSearchHead(self, packet_id, data, seq):
  1857. """ReqLayerDetailSearchHead packet.
  1858. ID: 64900100
  1859. JP: レイヤ検索詳細数要求
  1860. TR: Layer detail search count request
  1861. """
  1862. with pati.Unpacker(data) as unpacker:
  1863. self.search_info = {
  1864. "layer": unpacker.struct(">B")[0],
  1865. "search": unpacker.detailed_optional_fields(),
  1866. "offset": unpacker.struct(">I")[0],
  1867. "limit": unpacker.struct(">I")[0],
  1868. "layer_fields": unpacker.bytes(),
  1869. "user_fields": unpacker.bytes()
  1870. }
  1871. self.server.debug((
  1872. "ReqLayerDetailSearchHead("
  1873. "layer={layer!r}, search={search!r}, "
  1874. "offset={offset}, limit={limit}, "
  1875. "layer_fields={layer_fields!r}, user_fields={user_fields!r})"
  1876. ).format(**self.search_info))
  1877. self.sendAnsLayerDetailSearchHead(data, seq)
  1878. def sendAnsLayerDetailSearchHead(self, data, seq):
  1879. """AnsLayerDetailSearchHead packet.
  1880. ID: 64900200
  1881. JP: レイヤ検索詳細数返答
  1882. TR: Layer detail search count response
  1883. TODO: Find what to send.
  1884. """
  1885. unk1 = 0
  1886. unk2 = 0
  1887. self.search_data = self.session.layer_detail_search(
  1888. self.search_info["search"]["data"]
  1889. )
  1890. count = len(self.search_data)
  1891. data = struct.pack(">III", unk1, count, unk2)
  1892. self.send_packet(PatID4.AnsLayerDetailSearchHead, data, seq)
  1893. def recvReqLayerDetailSearchData(self, packet_id, data, seq):
  1894. """ReqLayerDetailSearchData packet.
  1895. ID: 64910100
  1896. JP: レイヤ検索詳細データ要求
  1897. TR: Layer detail search data request
  1898. TODO: Handle this request.
  1899. """
  1900. offset, count = struct.unpack_from(">II", data)
  1901. self.sendAnsLayerDetailSearchData(offset, count, seq)
  1902. def sendAnsLayerDetailSearchData(self, offset, count, seq):
  1903. """AnsLayerDetailSearchData packet.
  1904. ID: 64910200
  1905. JP: レイヤ検索詳細データ返答
  1906. TR: Layer detail search data response
  1907. TODO: Handle this response.
  1908. """
  1909. unk = 0
  1910. cities = self.search_data
  1911. data = struct.pack(">II", unk, len(cities))
  1912. for i, city in enumerate(cities):
  1913. with city.lock():
  1914. layer_data = pati.LayerData.create_from(i, city)
  1915. layer_data.assert_fields(self.search_info["layer_fields"])
  1916. data += layer_data.pack()
  1917. data += pati.pack_optional_fields(city.optional_fields)
  1918. with city.players.lock():
  1919. data += struct.pack(">I", len(city.players))
  1920. for _, player in city.players:
  1921. layer_user = pati.LayerUserInfo()
  1922. layer_user.capcom_id = pati.String(player.capcom_id)
  1923. layer_user.hunter_name = pati.String(
  1924. player.hunter_name
  1925. )
  1926. layer_user.assert_fields(
  1927. self.search_info["user_fields"]
  1928. )
  1929. data += layer_user.pack()
  1930. data += pati.pack_optional_fields(
  1931. player.get_optional_fields()
  1932. )
  1933. self.send_packet(PatID4.AnsLayerDetailSearchData, data, seq)
  1934. def recvReqLayerDetailSearchFoot(self, packet_id, data, seq):
  1935. """ReqLayerDetailSearchFoot packet.
  1936. ID: 64920100
  1937. JP: レイヤ検索詳細終了要求
  1938. TR: Layer detail search end of transmission request
  1939. """
  1940. self.sendAnsLayerDetailSearchFoot(data, seq)
  1941. def sendAnsLayerDetailSearchFoot(self, data, seq):
  1942. """AnsLayerDetailSearchFoot packet.
  1943. ID: 64920200
  1944. JP: レイヤ検索詳細終了返答
  1945. TR: Layer detail search end of transmission response
  1946. """
  1947. self.send_packet(PatID4.AnsLayerDetailSearchFoot, b"", seq)
  1948. def recvReqLayerCreateHead(self, packet_id, data, seq):
  1949. """ReqLayerCreateHead packet.
  1950. ID: 64110100
  1951. JP: レイヤ作成要求(番号指定)
  1952. TR: Layer creation request (number specified)
  1953. TODO: Lock it to prevent race-condition.
  1954. """
  1955. number, = struct.unpack(">H", data)
  1956. self.sendAnsLayerCreateHead(number, seq)
  1957. def sendAnsLayerCreateHead(self, number, seq):
  1958. """AnsLayerCreateHead packet.
  1959. ID: 64110200
  1960. JP: レイヤ作成返答
  1961. TR: Layer creation response
  1962. """
  1963. data = struct.pack(">H", number)
  1964. if not self.session.is_city_empty(number):
  1965. self.sendAnsAlert(PatID4.AnsLayerCreateHead,
  1966. "<LF=8><BODY><CENTER>City already exists.<END>",
  1967. seq)
  1968. return
  1969. if not self.session.reserve_city(number, True):
  1970. self.sendAnsAlert(PatID4.AnsLayerCreateHead,
  1971. "<LF=8><BODY><CENTER>City reserved.<END>",
  1972. seq)
  1973. return
  1974. self.send_packet(PatID4.AnsLayerCreateHead, data, seq)
  1975. path = self.session.get_layer_path()
  1976. path.city_id = number
  1977. self.notify_city_info_set(path)
  1978. def recvReqLayerCreateSet(self, packet_id, data, seq):
  1979. """ReqLayerCreateSet packet.
  1980. ID: 64120100
  1981. JP: レイヤ作成設定要求(番号指定)
  1982. TR: Layer creation settings request (number specified)
  1983. """
  1984. with pati.Unpacker(data) as unpacker:
  1985. number, = unpacker.struct(">H")
  1986. layer_set = unpacker.LayerSet()
  1987. extra = unpacker.optional_fields()
  1988. self.server.debug("LayerCreateSet: {}, {!r}, {!r}".format(
  1989. number, layer_set, extra))
  1990. self.sendAnsLayerCreateSet(number, layer_set, extra, seq)
  1991. def sendAnsLayerCreateSet(self, number, layer_set, extra, seq):
  1992. """AnsLayerCreateSet packet.
  1993. ID: 64120200
  1994. JP: レイヤ作成設定返答
  1995. TR: Layer creation settings response
  1996. """
  1997. data = struct.pack(">H", number)
  1998. self.session.layer_create(number, layer_set, extra)
  1999. self.send_packet(PatID4.AnsLayerCreateSet, data, seq)
  2000. path = self.session.get_layer_path()
  2001. self.notify_city_number_set(path)
  2002. def recvReqLayerCreateFoot(self, packet_id, data, seq):
  2003. """ReqLayerCreateFoot packet.
  2004. ID: 64130100
  2005. JP: レイヤ作成完了要求(番号指定)
  2006. TR: Layer creation end of transmission request
  2007. """
  2008. number, unk = struct.unpack(">HB", data)
  2009. self.session.reserve_city(number, False)
  2010. self.sendAnsLayerCreateFoot(number, unk, seq)
  2011. def sendAnsLayerCreateFoot(self, number, unk, seq):
  2012. """AnsLayerCreateFoot packet.
  2013. ID: 64130200
  2014. JP: レイヤ作成完了返答
  2015. TR: Layer creation end of transmission response
  2016. """
  2017. data = struct.pack(">H", number)
  2018. self.send_packet(PatID4.AnsLayerCreateFoot, data, seq)
  2019. path = self.session.get_layer_path()
  2020. path.city_id = number
  2021. self.notify_city_info_set(path)
  2022. def recvReqLayerUp(self, packet_id, data, seq):
  2023. """ReqLayerUp packet.
  2024. ID: 64150100
  2025. JP: レイヤアップ要求
  2026. TR: Layer up request
  2027. Sent by the game when leaving the gate via the entrance:
  2028. - Relocate > Select Server
  2029. """
  2030. self.sendAnsLayerUp(data, seq)
  2031. def sendAnsLayerUp(self, data, seq):
  2032. """AnsLayerUp packet.
  2033. ID: 64150200
  2034. JP: レイヤアップ返答
  2035. TR: Layer up response
  2036. """
  2037. self.notify_layer_departure(False)
  2038. self.send_packet(PatID4.AnsLayerUp, b"", seq)
  2039. @staticmethod
  2040. def packNtcLayerInfoSet(layer_path, layer_data, optional_fields):
  2041. # type: (pati.LayerPath, pati.LayerData, List[int]) -> bytes
  2042. """NtcLayerInfoSet packet.
  2043. ID: 64201000
  2044. JP: レイヤ情報設定通知
  2045. TR: Layer information setting notification
  2046. """
  2047. data = pati.lp2_string(layer_path.pack())
  2048. data += layer_data.pack()
  2049. data += pati.pack_optional_fields(optional_fields)
  2050. return data
  2051. def recvReqLayerMediationList(self, packet_id, data, seq):
  2052. """ReqLayerMediationList packet.
  2053. ID: 64820100
  2054. JP: レイヤ調停データリスト取得要求
  2055. TR: Get layer mediation list request
  2056. """
  2057. unk1, unk2 = struct.unpack_from(">BB", data)
  2058. unk3 = data[2:]
  2059. self.sendAnsLayerMediationList(unk1, unk2, unk3, seq)
  2060. def sendAnsLayerMediationList(self, unk1, unk2, unk3, seq):
  2061. """AnsLayerMediationList packet.
  2062. ID: 64820200
  2063. JP: レイヤ調停データリスト取得返答
  2064. TR: Get layer mediation list response
  2065. TODO: Store the item list and its state in the city.
  2066. """
  2067. unk = 0
  2068. count = 14
  2069. data = struct.pack(">BB", unk, count)
  2070. for i in range(1, count+1):
  2071. item = pati.MediationListItem()
  2072. item.name = pati.String(b"Test")
  2073. item.index = pati.Byte(i)
  2074. item.is_locked = pati.Byte(0)
  2075. data += item.pack()
  2076. self.send_packet(PatID4.AnsLayerMediationList, data, seq)
  2077. def recvReqLayerMediationLock(self, packet_id, data, seq):
  2078. """ReqLayerMediationLock packet.
  2079. ID: 64800100
  2080. JP: レイヤ調停データ確保要求
  2081. TR: Layer mediation data lock request
  2082. Sent by the game when the player want to acquire a resource that
  2083. cannot be shared by multiple players at the same time.
  2084. - Seats are from index 1 to 12
  2085. - Arm wrestling is from index 13 to 14
  2086. """
  2087. index, = struct.unpack_from(">B", data)
  2088. mediation_data = pati.MediationListItem.unpack(data, 1)
  2089. self.server.debug("LayerMediationLock: {}, {!r}".format(
  2090. index, mediation_data))
  2091. self.sendAnsLayerMediationLock(index, mediation_data, seq)
  2092. def sendAnsLayerMediationLock(self, index, mediation_data, seq):
  2093. """AnsLayerMediationLock packet.
  2094. ID: 64800200
  2095. JP: レイヤ調停データ確保返答
  2096. TR: Layer mediation data lock response
  2097. TODO: Enable notifications and handle player disconnection.
  2098. """
  2099. success = 1
  2100. data = struct.pack(">B", success)
  2101. # self.sendNtcLayerMediationLock(index, mediation_data, seq)
  2102. self.send_packet(PatID4.AnsLayerMediationLock, data, seq)
  2103. def sendNtcLayerMediationLock(self, index, mediation_data, seq):
  2104. """NtcLayerMediationLock packet.
  2105. ID: 64801000
  2106. JP: レイヤ調停データ確保通知
  2107. TR: Layer mediation data lock notification
  2108. """
  2109. data = pati.lp2_string(self.session.capcom_id)
  2110. data += struct.pack(">B", index)
  2111. data += mediation_data.pack()
  2112. self.server.layer_broadcast(self.session,
  2113. PatID4.NtcLayerMediationLock, data, seq)
  2114. def recvReqLayerMediationUnlock(self, packet_id, data, seq):
  2115. """ReqLayerMediationUnlock packet.
  2116. ID: 64810100
  2117. JP: レイヤ調停データ開放要求
  2118. TR: Layer mediation data unlock request
  2119. """
  2120. index, = struct.unpack_from(">B", data)
  2121. mediation_data = pati.MediationListItem.unpack(data, 1)
  2122. self.server.debug("LayerMediationUnlock: {}, {!r}".format(
  2123. index, mediation_data))
  2124. self.sendAnsLayerMediationUnlock(index, mediation_data, seq)
  2125. def sendAnsLayerMediationUnlock(self, index, mediation_data, seq):
  2126. """AnsLayerMediationUnlock packet.
  2127. ID: 64810200
  2128. JP: レイヤ調停データ開放要求
  2129. TR: Layer mediation data unlock response
  2130. TODO: Enable notifications and handle player disconnection.
  2131. """
  2132. success = 1
  2133. data = struct.pack(">B", success)
  2134. # self.sendNtcLayerMediationUnlock(index, mediation_data, seq)
  2135. self.send_packet(PatID4.AnsLayerMediationUnlock, data, seq)
  2136. def sendNtcLayerMediationUnlock(self, index, mediation_data, seq):
  2137. """NtcLayerMediationUnlock packet.
  2138. ID: 64811000
  2139. JP: レイヤ調停データ開放通知
  2140. TR: Layer mediation data unlock notification
  2141. """
  2142. data = pati.lp2_string(self.session.capcom_id)
  2143. data += struct.pack(">B", index)
  2144. data += mediation_data.pack()
  2145. self.server.layer_broadcast(self.session,
  2146. PatID4.NtcLayerMediationUnlock, data, seq)
  2147. def sendNtcLayerHost(self, new_leader, seq):
  2148. """NtcLayerHost packet.
  2149. ID: 64411000
  2150. JP: レイヤのホスト通知
  2151. TR: Layer host notification
  2152. """
  2153. data = struct.pack(">HII", 0x08, 0x00, 0x00) # unk short array patitem
  2154. data += pati.lp2_string(new_leader.capcom_id)
  2155. data += pati.lp2_string(new_leader.hunter_name)
  2156. self.server.layer_broadcast(self.session, PatID4.NtcLayerHost, data,
  2157. seq)
  2158. def sendNtcCircleHostHandover(self, circle, new_leader, new_leader_index,
  2159. seq):
  2160. """NtcCircleHostHandover packet.
  2161. ID: 65401000
  2162. JP: サークルのホスト移譲通知
  2163. TR: Circle host transfer notice
  2164. This packet is presently unused as it does not appear to have
  2165. any valid callback function branch within Monster Hunter 3.
  2166. """
  2167. unk1 = 0
  2168. data = struct.pack(">IB", unk1, new_leader_index + 1)
  2169. data += pati.lp2_string(new_leader.capcom_id)
  2170. data += pati.lp2_string(new_leader.hunter_name)
  2171. data += pati.lp2_string(b"") # Unk max-1 length short array
  2172. self.server.circle_broadcast(circle, PatID4.NtcCircleHostHandover,
  2173. data, seq, self.session)
  2174. def sendNtcCircleHost(self, circle, new_leader, new_leader_index, seq):
  2175. """NtcCircleHost packet.
  2176. ID: 65411000
  2177. JP: サークルのホスト通知
  2178. TR: Circle host notification
  2179. """
  2180. unk1 = 0
  2181. data = struct.pack(">IB", unk1, new_leader_index + 1)
  2182. data += pati.lp2_string(new_leader.capcom_id)
  2183. data += pati.lp2_string(new_leader.hunter_name)
  2184. self.server.circle_broadcast(circle, PatID4.NtcCircleHost, data,
  2185. seq, self.session)
  2186. def notify_city_info_set(self, path):
  2187. # type: (pati.LayerPath) -> None
  2188. city = self.get_layer(path)
  2189. assert isinstance(city, db.City)
  2190. gate = city.parent
  2191. layer_data = pati.LayerData.create_from(path.city_id, city, path)
  2192. info_set = self.packNtcLayerInfoSet(path, layer_data,
  2193. city.optional_fields)
  2194. self.server.broadcast(gate.players, PatID4.NtcLayerInfoSet, info_set, 0,
  2195. self.session)
  2196. def notify_city_number_set(self, path):
  2197. # type: (pati.LayerPath) -> None
  2198. city = self.get_layer(path)
  2199. assert isinstance(city, db.City)
  2200. gate = city.parent
  2201. layer_data = pati.LayerData.create_from(path.city_id, city, path)
  2202. number_set = self.packNtcLayerUserNum(4, layer_data)
  2203. self.server.broadcast(gate.players, PatID4.NtcLayerUserNum, number_set, 0,
  2204. self.session)
  2205. @staticmethod
  2206. def get_layer(path):
  2207. # type: (pati.LayerPath) -> Optional[db.Server | db.Gate | db.City]
  2208. database = db.get_instance()
  2209. if path.city_id > 0:
  2210. return database.get_city(path.server_id, path.gate_id, path.city_id)
  2211. elif path.gate_id > 0:
  2212. return database.get_gate(path.server_id, path.gate_id)
  2213. elif path.server_id > 0:
  2214. return database.get_server(path.server_id)
  2215. return None
  2216. def notify_layer_departure(self, end):
  2217. # type: (bool) -> None
  2218. path = self.session.get_layer_path()
  2219. if self.session.layer == 2:
  2220. new_host = self.session.try_transfer_city_leadership()
  2221. if new_host:
  2222. self.sendNtcLayerHost(new_host, 0)
  2223. if self.session.layer > 0:
  2224. ntc_data = pati.lp2_string(self.session.capcom_id)
  2225. self.server.layer_broadcast(self.session, PatID4.NtcLayerOut,
  2226. ntc_data, 0)
  2227. if self.session.local_info['circle_id'] is not None:
  2228. self.notify_circle_leave(self.session.local_info['circle_id'] + 1,
  2229. seq=0)
  2230. if end:
  2231. self.session.layer_end()
  2232. else:
  2233. self.session.layer_up()
  2234. if path.city_id > 0:
  2235. city = self.get_layer(path)
  2236. assert isinstance(city, db.City)
  2237. self.notify_city_number_set(path)
  2238. if city.leader is None:
  2239. self.notify_city_info_set(path)
  2240. def notify_circle_leave(self, circle_index, seq):
  2241. circle = self.session.get_circle()
  2242. with circle.lock():
  2243. self.sendNtcCircleLeave(circle, circle_index, seq)
  2244. if circle.leader == self.session:
  2245. if circle.departed:
  2246. new_host_index, new_host = \
  2247. self.session.try_transfer_circle_leadership()
  2248. if new_host:
  2249. self.sendNtcCircleHost(
  2250. circle, new_host, new_host_index, seq
  2251. )
  2252. else:
  2253. self.sendNtcCircleBreak(circle, seq)
  2254. self.session.leave_circle()
  2255. self.sendNtcCircleListLayerChange(circle, circle_index, seq)
  2256. def on_exception(self, e):
  2257. # type: (Exception) -> None
  2258. self.server.error(traceback.format_exc())
  2259. self.send_error("{}: {}".format(type(e).__name__, str(e)))
  2260. def on_finish(self):
  2261. self.notify_layer_departure(True)
  2262. self.session.disconnect()
  2263. self.session.delete()
  2264. self.server.del_from_debug(self)
  2265. self.server.info("Client finished!")
  2266. def on_packet(self, data):
  2267. if not data:
  2268. self.finish()
  2269. return
  2270. packet_id, data, seq = data
  2271. self.server.info(
  2272. "RECV %s[ID=%08x; Seq=%04x]",
  2273. PAT_NAMES.get(packet_id, "Packet"),
  2274. packet_id, seq
  2275. )
  2276. self.server.debug("%s", hexdump(data))
  2277. self.dispatch(packet_id, data, seq)
  2278. def send_packet(self, packet_id=0, data=b'', seq=0):
  2279. super(PatRequestHandler, self).send_packet(packet_id, data, seq)
  2280. self.server.info(
  2281. "SEND %s[ID=%08x; Seq=%04x]",
  2282. PAT_NAMES.get(packet_id, "Packet"),
  2283. packet_id, seq
  2284. )
  2285. self.server.debug("%s", hexdump(data))
  2286. def dispatch(self, packet_id, data, seq):
  2287. """Packet dispatcher."""
  2288. if packet_id not in PAT_NAMES:
  2289. self.server.error("Unknown packet ID: %08x", packet_id)
  2290. return
  2291. name = "recv{}".format(PAT_NAMES[packet_id])
  2292. if not hasattr(self, name):
  2293. self.server.error("Unsupported packet: %08x | %s", packet_id, name)
  2294. return
  2295. handler = getattr(self, name)
  2296. return handler(packet_id, data, seq)
  2297. def on_tick(self):
  2298. if not self.requested_connection:
  2299. # TODO: Investigate why do we need to wait a certain amount of
  2300. # seconds before sending the `ReqConnection` packet?
  2301. if self.ping_timer.elapsed() >= 1.5:
  2302. self.requested_connection = True
  2303. self.sendReqConnection()
  2304. return
  2305. # Send a ping with 30 seconds interval
  2306. if self.ping_timer.elapsed() >= 30:
  2307. if not self.server.debug_enabled() and not self.line_check:
  2308. raise Exception("Client timed out.")
  2309. self.line_check = False
  2310. self.sendReqLineCheck()
  2311. self.ping_timer.restart()