HLMOD.HU Forrás Megtekintés - www.hlmod.hu
  1.  
  2. #include <amxmodx>
  3.  
  4. #include <regex>
  5. #include <sockets_hz>
  6. #include <fakemeta>
  7.  
  8. #include <hamsandwich>
  9.  
  10. new const Plugin[] = "Steam Friends Highlighter"
  11. new const Author[] = "joaquimandrade"
  12. new const Version[] = "1.1"
  13.  
  14. new const VoogruMagicNumber[] = "76561197960265728"
  15.  
  16. new RequestStringFormatPre[] = "GET "
  17. new RequestStringFormatPost[] = " HTTP/1.1^nHOST: steamcommunity.com^nConnection: close^n^n^n^n";
  18.  
  19. const BufferSize = 1000
  20.  
  21. const MaxSlots = 32
  22.  
  23. new Buffers[MaxSlots+1][BufferSize]
  24. new BufferHelper[BufferSize]
  25.  
  26. new bool:isFriend[MaxSlots+1][MaxSlots+1]
  27.  
  28. new MaxPlayers
  29.  
  30. enum Regexes
  31. {
  32. RegexProfileToID,
  33. RegexName,
  34. RegexFriendData
  35. }
  36.  
  37. new RegexesText[Regexes][] =
  38. {
  39. "Location: http://steamcommunity\.com(/id/([^^/]*)/friends)",
  40. "(^" href=^".*?^">Return to ([^^']*)'s profile.*?<div id=^"memberList^">\s*)",
  41. "(<div onClick=^"top\.location\.href='http://steamcommunity.com/(profiles||id)/([^^']*?)'^" class=^"([^^^"]*?)^">.*?</p>\s*</div>\s*(?:<br clear=^"all^" />|)\s*)"
  42. }
  43.  
  44. new Regex:RegexesCompiled[Regexes]
  45.  
  46. new Sockets[MaxSlots+1]
  47. new bool:SocketIsWriteable[MaxSlots+1]
  48.  
  49. new ProfileFormatString[] = "/profiles/%s/friends"
  50. new ProfileString[sizeof ProfileFormatString + sizeof VoogruMagicNumber]
  51.  
  52. new Trie:SteamIDToProfile
  53. new Trie:SteamIDToProfileStringListID
  54. new Trie:ProfileToServerID
  55. new Array:ProfileStringsList
  56.  
  57. new ProfileStringListIDs[MaxSlots+1]
  58.  
  59. new Profiles[MaxSlots+1][sizeof VoogruMagicNumber]
  60.  
  61. new Trie:IDToProfile
  62.  
  63. new ID[sizeof VoogruMagicNumber]
  64.  
  65. const PlayerSteamNameMaxLen = 32
  66. new PlayerSteamNames[MaxSlots+1][PlayerSteamNameMaxLen]
  67.  
  68. enum PlayerCommunicationState
  69. {
  70. CheckingIfPageHasID,
  71. StartPageParsing,
  72. PageParsingSteamName,
  73. PageParsingFriends
  74. }
  75.  
  76. new PlayerCommunicationState:PlayersCommunicationState[MaxSlots+1]
  77.  
  78. new Float:TaskDelay = 1.0
  79.  
  80. new Array:ConnectionQueue
  81. new Array:CommunicationQueue
  82. new Array:RequestsQueue
  83.  
  84. new IsHighlightingFriends[MaxSlots+1]
  85.  
  86. const TransparencyAmountDefault = 255
  87.  
  88. new CurrentTransparencyAmount[MaxSlots+1]
  89. new SpeedMultiplier[MaxSlots+1]
  90.  
  91. new ForwardAddToFullPack
  92. new HighlightingN
  93.  
  94. new CvarSteamHighlightSpeed
  95. new CvarSteamHighlightMinTrans
  96.  
  97. new Array:FriendProfiles[MaxSlots+1]
  98. new Array:FriendIDs[MaxSlots+1]
  99.  
  100. public plugin_init()
  101. {
  102. register_plugin(Plugin,Version,Author)
  103.  
  104. register_clcmd("+steam","highlightFriendsStart")
  105. register_clcmd("-steam","highlightFriendsStop")
  106.  
  107. register_clcmd("steam_toggle","steamToggle")
  108.  
  109. register_dictionary("steamFriendsHighlighter.txt")
  110.  
  111. CvarSteamHighlightSpeed = register_cvar("steamHighlight_speed","3")
  112. CvarSteamHighlightMinTrans = register_cvar("steamHighlight_min_trans","100")
  113.  
  114. RegisterHam(Ham_Spawn,"player","playerSpawn",1)
  115.  
  116. register_cvar("steamFriendsHighlighter",Version,FCVAR_SERVER|FCVAR_SPONLY)
  117. }
  118.  
  119. public plugin_cfg()
  120. {
  121. new regexErrorCode
  122. new regexErrorString[100]
  123.  
  124. for(new Regexes:i=Regexes:0;i<Regexes;i++)
  125. {
  126. RegexesCompiled[i] = regex_compile(RegexesText[i],regexErrorCode,regexErrorString,charsmax(regexErrorString),"s");
  127. }
  128.  
  129. SteamIDToProfileStringListID = TrieCreate()
  130. IDToProfile = TrieCreate()
  131. SteamIDToProfile = TrieCreate()
  132. ProfileToServerID = TrieCreate()
  133.  
  134. ProfileStringsList = ArrayCreate(sizeof ProfileString)
  135.  
  136. MaxPlayers = get_maxplayers()
  137.  
  138. ConnectionQueue = ArrayCreate()
  139. CommunicationQueue = ArrayCreate()
  140. RequestsQueue = ArrayCreate()
  141.  
  142. for(new id=1;id<=MaxPlayers;id++)
  143. {
  144. FriendProfiles[id] = ArrayCreate(sizeof VoogruMagicNumber)
  145. FriendIDs[id] = ArrayCreate(sizeof ID)
  146. }
  147.  
  148. set_task(TaskDelay,"processCommunicationQueue",.flags="b")
  149. }
  150.  
  151. public playerSpawn(id)
  152. {
  153. if(is_user_alive(id))
  154. {
  155. static profile[sizeof VoogruMagicNumber]
  156. static idString[sizeof VoogruMagicNumber]
  157.  
  158. static friendID
  159.  
  160. for(new i=0;i<ArraySize(FriendProfiles[id]);i++)
  161. {
  162. ArrayGetString(FriendProfiles[id],i,profile,charsmax(profile))
  163.  
  164. if(TrieGetCell(ProfileToServerID,profile,friendID))
  165. {
  166. ArrayDeleteItem(FriendProfiles[id],i)
  167. i--
  168.  
  169. isFriend[id][friendID] = true
  170. isFriend[friendID][id] = true
  171. }
  172. }
  173.  
  174. for(new i=0;i<ArraySize(FriendIDs[id]);i++)
  175. {
  176. ArrayGetString(FriendIDs[id],i,idString,charsmax(idString))
  177.  
  178. if(TrieGetString(IDToProfile,idString,profile,charsmax(profile)))
  179. {
  180. if(TrieGetCell(ProfileToServerID,profile,friendID))
  181. {
  182. ArrayDeleteItem(FriendIDs[id],i)
  183. i--
  184.  
  185. isFriend[id][friendID] = true
  186. isFriend[friendID][id] = true
  187. }
  188. }
  189. }
  190. }
  191. }
  192.  
  193. public processCommunicationQueue()
  194. {
  195. if(ArraySize(CommunicationQueue))
  196. {
  197. new id = ArrayGetCell(CommunicationQueue,0)
  198. ArrayDeleteItem(CommunicationQueue,0)
  199.  
  200. checkPlayerSocket(id)
  201. }
  202. else if(ArraySize(RequestsQueue))
  203. {
  204. new id = ArrayGetCell(RequestsQueue,0)
  205. ArrayDeleteItem(RequestsQueue,0)
  206.  
  207. makeRequest(id,Sockets[id])
  208. }
  209. else if(ArraySize(ConnectionQueue))
  210. {
  211. new id = ArrayGetCell(ConnectionQueue,0)
  212. ArrayDeleteItem(ConnectionQueue,0)
  213.  
  214. initConnection(id)
  215. }
  216.  
  217. }
  218.  
  219. steamIDToCommunityID(steamID[],communityID[sizeof VoogruMagicNumber])
  220. {
  221. const leftMaxLen = 8
  222. const rightMaxLen = 20
  223.  
  224. new left[leftMaxLen];
  225. new right[rightMaxLen];
  226.  
  227. strtok(steamID, left, leftMaxLen-1, right, rightMaxLen-1, ':')
  228. strtok(right, left, leftMaxLen-1, right, rightMaxLen-1, ':')
  229.  
  230. new iServer = str_to_num(left);
  231. new iAuthID = str_to_num(right);
  232.  
  233. const lastIndex = charsmax(VoogruMagicNumber) - 1
  234. copy(communityID,charsmax(VoogruMagicNumber),VoogruMagicNumber)
  235.  
  236. new toAdd = iAuthID * 2 + iServer;
  237.  
  238. new toAddString[sizeof VoogruMagicNumber]
  239. num_to_str(toAdd,toAddString,charsmax(VoogruMagicNumber));
  240.  
  241. new addLastIndex = strlen(toAddString) - 1;
  242.  
  243. for(new i=0;i<=addLastIndex;i++)
  244. {
  245. new num = toAddString[addLastIndex - i] - 48;
  246.  
  247. new j=lastIndex - i;
  248.  
  249. do
  250. {
  251. new num2 = communityID[j] - 48;
  252. new sum = num + num2;
  253.  
  254. communityID[j] = (sum % 10) + 48;
  255.  
  256. num = sum / 10;
  257.  
  258. j--;
  259. }
  260. while(num);
  261. }
  262. }
  263.  
  264. initConnection(id)
  265. {
  266. static steamID[34]
  267. get_user_authid(id,steamID,charsmax(steamID))
  268.  
  269. new socket = initRequest(id)
  270.  
  271. if(socket > 0)
  272. {
  273. new profileStringListID
  274.  
  275. static profile[sizeof VoogruMagicNumber]
  276.  
  277. if(TrieGetCell(SteamIDToProfileStringListID,steamID,profileStringListID))
  278. {
  279. ArrayGetString(ProfileStringsList,profileStringListID,ProfileString,charsmax(ProfileString))
  280.  
  281. TrieGetString(SteamIDToProfile,steamID,profile,charsmax(profile))
  282. }
  283. else
  284. {
  285. TrieSetCell(SteamIDToProfileStringListID,steamID,profileStringListID=ArraySize(ProfileStringsList))
  286.  
  287. steamIDToCommunityID(steamID,profile)
  288.  
  289. formatex(ProfileString,charsmax(ProfileString),ProfileFormatString,profile)
  290. ArrayPushString(ProfileStringsList,ProfileString)
  291.  
  292. TrieSetString(SteamIDToProfile,steamID,profile)
  293. }
  294.  
  295. copy(Profiles[id],charsmax(profile),profile)
  296.  
  297. TrieSetCell(ProfileToServerID,profile,id)
  298.  
  299. ProfileStringListIDs[id] = profileStringListID
  300.  
  301. ArrayPushCell(RequestsQueue,id)
  302. }
  303. }
  304.  
  305. public client_authorized(id)
  306. {
  307. ArrayClear(FriendProfiles[id])
  308. ArrayClear(FriendIDs[id])
  309.  
  310. PlayersCommunicationState[id] = CheckingIfPageHasID
  311.  
  312. new buffer[BufferSize]
  313. Buffers[id] = buffer
  314.  
  315. for(new i=1;i<=MaxPlayers;i++)
  316. isFriend[id][i] = false
  317.  
  318. ArrayPushCell(ConnectionQueue,id)
  319. }
  320.  
  321. cleanArrayElement(Array:array,element)
  322. {
  323. for(new i=0;i<ArraySize(array);i++)
  324. {
  325. if(ArrayGetCell(array,i) == element)
  326. {
  327. ArrayDeleteItem(array,i)
  328. i--
  329. }
  330. }
  331. }
  332.  
  333. public client_disconnect(id)
  334. {
  335. highlightFriendsStop(id)
  336.  
  337. cleanArrayElement(ConnectionQueue,id)
  338. cleanArrayElement(CommunicationQueue,id)
  339. cleanArrayElement(RequestsQueue,id)
  340.  
  341. if(TrieKeyExists(ProfileToServerID,Profiles[id]))
  342. {
  343. TrieDeleteKey(ProfileToServerID,Profiles[id])
  344. }
  345.  
  346. if(Sockets[id])
  347. {
  348. closeUserSocket(id)
  349. }
  350.  
  351. static name[32]
  352. get_user_name(id,name,charsmax(name))
  353.  
  354. for(new i=1;i<=MaxPlayers;i++)
  355. {
  356. if(isFriend[i][id])
  357. {
  358. if(equal(PlayerSteamNames[id],name))
  359. {
  360. client_print(i,print_chat,"%L",i,"FRIEND_LEFT_SAME_NAME",name)
  361. }
  362. else
  363. {
  364. client_print(i,print_chat,"%L",i,"FRIEND_LEFT",PlayerSteamNames[id],name)
  365. }
  366.  
  367. isFriend[i][id] = false
  368. }
  369. }
  370. }
  371.  
  372. initRequest(id)
  373. {
  374. static error
  375.  
  376. new socket = socket_open_non_blocking("www.steamcommunity.com",80,SOCKET_TCP,error);
  377.  
  378. Sockets[id] = socket
  379. SocketIsWriteable[id] = false
  380.  
  381. return socket
  382. }
  383.  
  384. makeRequest(id,socket)
  385. {
  386. SocketIsWriteable[id] = socket_is_writable(socket)
  387.  
  388. if(SocketIsWriteable[id])
  389. {
  390. ArrayGetString(ProfileStringsList,ProfileStringListIDs[id],ProfileString,charsmax(ProfileString))
  391.  
  392. socket_send(socket,RequestStringFormatPre,charsmax(RequestStringFormatPre))
  393. socket_send(socket,ProfileString,charsmax(ProfileString))
  394. socket_send(socket,RequestStringFormatPost,charsmax(RequestStringFormatPost))
  395.  
  396. ArrayPushCell(CommunicationQueue,id)
  397. }
  398. else
  399. {
  400. //processCommunicationQueue()
  401. ArrayPushCell(RequestsQueue,id)
  402. }
  403. }
  404.  
  405. closeUserSocket(id)
  406. {
  407. socket_close(Sockets[id])
  408. Sockets[id] = 0
  409. }
  410.  
  411. processData(id,socket,buffer[],len)
  412. {
  413. switch(PlayersCommunicationState[id])
  414. {
  415. case CheckingIfPageHasID:
  416. {
  417. static profileToIDRedirectStatusString[] = "HTTP/1.1 302 Found"
  418.  
  419. if(equal(buffer,profileToIDRedirectStatusString,charsmax(profileToIDRedirectStatusString)))
  420. {
  421. closeUserSocket(id)
  422.  
  423. new Regex:regexCompiled = Regex:RegexesCompiled[RegexProfileToID]
  424.  
  425. new results
  426. regex_match_c(buffer,regexCompiled,results);
  427.  
  428. if(results)
  429. {
  430. regex_substr(regexCompiled,1,ProfileString,charsmax(ProfileString));
  431.  
  432. ArraySetString(ProfileStringsList,ProfileStringListIDs[id],ProfileString)
  433.  
  434. new socket = initRequest(id)
  435.  
  436. if(socket)
  437. {
  438. buffer[0] = 0
  439. PlayersCommunicationState[id] = StartPageParsing
  440.  
  441. ArrayPushCell(RequestsQueue,id)
  442. }
  443.  
  444. regex_substr(regexCompiled,2,ID,charsmax(ID))
  445.  
  446. static steamID[34]
  447. get_user_authid(id,steamID,charsmax(steamID))
  448.  
  449. TrieSetString(IDToProfile,ID,Profiles[id])
  450. }
  451. }
  452. else
  453. {
  454. PlayersCommunicationState[id] = StartPageParsing
  455. processData(id,socket,buffer,len)
  456. }
  457. }
  458. case StartPageParsing:
  459. {
  460. static startText[] = "linkStandard"
  461.  
  462. new position = contain(buffer,startText)
  463.  
  464. if(position != -1)
  465. {
  466. new storeFrom = position + charsmax(startText)
  467. format(buffer,BufferSize,buffer[storeFrom])
  468. PlayersCommunicationState[id] = PageParsingSteamName
  469. }
  470. else
  471. {
  472. buffer[0] = 0
  473. }
  474.  
  475. checkSocketData(id,socket)
  476. }
  477. case PageParsingSteamName:
  478. {
  479. new Regex:regexCompiled = Regex:RegexesCompiled[RegexName]
  480.  
  481. new results
  482. regex_match_c(buffer,regexCompiled,results);
  483.  
  484. if(results)
  485. {
  486. regex_substr(regexCompiled,1,BufferHelper,charsmax(BufferHelper));
  487. regex_substr(regexCompiled,2,PlayerSteamNames[id],PlayerSteamNameMaxLen)
  488.  
  489. format(buffer,BufferSize,buffer[strlen(BufferHelper)])
  490.  
  491. PlayersCommunicationState[id] = PageParsingFriends
  492.  
  493. processData(id,socket,buffer,len)
  494. }
  495. }
  496. case PageParsingFriends:
  497. {
  498. new Regex:regexCompiled = Regex:RegexesCompiled[RegexFriendData]
  499.  
  500. new results
  501. regex_match_c(buffer,regexCompiled,results);
  502.  
  503. if(results)
  504. {
  505. regex_substr(regexCompiled,1,BufferHelper,charsmax(BufferHelper));
  506.  
  507. static idTypeString[] = "profiles"
  508.  
  509. regex_substr(regexCompiled,2,idTypeString,charsmax(idTypeString));
  510.  
  511. static idString[sizeof VoogruMagicNumber]
  512.  
  513. regex_substr(regexCompiled,3,idString,charsmax(idString));
  514.  
  515. static inGameClass[] = "friendBlock_in-game"
  516. static class[sizeof inGameClass]
  517.  
  518. regex_substr(regexCompiled,4,class,charsmax(class));
  519.  
  520. if(equal(class,inGameClass))
  521. {
  522. static profile[sizeof VoogruMagicNumber]
  523.  
  524. new bool:hasProfile = true
  525.  
  526. if(equal(idTypeString,"id"))
  527. {
  528. hasProfile = TrieGetString(IDToProfile,idString,profile,charsmax(profile))
  529. }
  530. else
  531. {
  532. copy(profile,charsmax(profile),idString)
  533. }
  534.  
  535. if(hasProfile)
  536. {
  537. static friendID
  538.  
  539. if(TrieGetCell(ProfileToServerID,profile,friendID))
  540. {
  541. isFriend[id][friendID] = true
  542. isFriend[friendID][id] = true
  543.  
  544. static name[32]
  545. get_user_name(id,name,charsmax(name))
  546.  
  547. if(equal(name,PlayerSteamNames[id]))
  548. {
  549. client_print(friendID,print_chat,"%L",friendID,"FRIEND_JOINED_SAME_NAME",name)
  550. }
  551. else
  552. {
  553. client_print(friendID,print_chat,"%L",friendID,"FRIEND_JOINED",PlayerSteamNames[id],name)
  554. }
  555. }
  556. else
  557. {
  558. ArrayPushString(FriendProfiles[id],profile)
  559. }
  560. }
  561. else
  562. {
  563. ArrayPushString(FriendIDs[id],idString)
  564. }
  565.  
  566. format(buffer,BufferSize,buffer[strlen(BufferHelper)])
  567. processData(id,socket,buffer,len)
  568. }
  569. }
  570. else
  571. {
  572. checkSocketData(id,socket)
  573. }
  574. }
  575. }
  576. }
  577.  
  578. checkSocketData(id,socket)
  579. {
  580. new storeAt = strlen(Buffers[id])
  581. new toReceive = BufferSize - 1 - storeAt
  582.  
  583. if(toReceive)
  584. {
  585. new received = socket_recv(socket,Buffers[id][storeAt],toReceive + 1)
  586.  
  587. if(received)
  588. {
  589. if(received == toReceive)
  590. {
  591. processData(id,socket,Buffers[id],storeAt + received)
  592. }
  593. else
  594. {
  595. ArrayPushCell(CommunicationQueue,id)
  596. }
  597. }
  598. else
  599. {
  600. processData(id,socket,Buffers[id],strlen(Buffers[id]))
  601. }
  602. }
  603. else
  604. {
  605. closeUserSocket(id)
  606. }
  607. }
  608.  
  609. public checkPlayerSocketFromTask(params[])
  610. {
  611. checkPlayerSocket(params[0])
  612. }
  613.  
  614. checkPlayerSocket(id)
  615. {
  616. new socket = Sockets[id]
  617.  
  618. if(socket)
  619. {
  620. if(socket_change(socket))
  621. {
  622. checkSocketData(id,socket)
  623. }
  624. else
  625. {
  626. processCommunicationQueue()
  627. ArrayPushCell(CommunicationQueue,id)
  628. }
  629. }
  630. }
  631.  
  632. public highlightFriendsStart(id)
  633. {
  634. if(IsHighlightingFriends[id])
  635. {
  636. highlightFriendsStop(id)
  637. }
  638.  
  639. CurrentTransparencyAmount[id] = TransparencyAmountDefault
  640. SpeedMultiplier[id] = -1
  641.  
  642. if(!HighlightingN++)
  643. {
  644. ForwardAddToFullPack = register_forward(FM_AddToFullPack,"addToFullPackPost",1)
  645. }
  646.  
  647. IsHighlightingFriends[id] = true
  648.  
  649. return PLUGIN_HANDLED
  650. }
  651.  
  652. public highlightFriendsStop(id)
  653. {
  654. if(IsHighlightingFriends[id])
  655. {
  656. if(!--HighlightingN)
  657. {
  658. unregister_forward(FM_AddToFullPack,ForwardAddToFullPack,1)
  659. }
  660.  
  661. IsHighlightingFriends[id] = false
  662. }
  663.  
  664. return PLUGIN_HANDLED
  665. }
  666.  
  667. public addToFullPackPost(es, e, ent, host, hostflags, player, pSet)
  668. {
  669. if(player && IsHighlightingFriends[host])
  670. {
  671. if(host == ent)
  672. {
  673. new speed = get_pcvar_num(CvarSteamHighlightSpeed)
  674. new minTrans = clamp(get_pcvar_num(CvarSteamHighlightMinTrans),0,255)
  675. new currentTrans = CurrentTransparencyAmount[host]
  676. new speedMultiplier = SpeedMultiplier[host]
  677.  
  678.  
  679. if(currentTrans < minTrans)
  680. {
  681. speedMultiplier = 0
  682.  
  683. currentTrans = minTrans
  684. }
  685. else if(currentTrans == minTrans)
  686. {
  687. speedMultiplier = 1
  688. }
  689.  
  690. if(currentTrans > 255)
  691. {
  692. speedMultiplier = 0
  693.  
  694. currentTrans = 255
  695. }
  696. else if(currentTrans == 255)
  697. {
  698. speedMultiplier = -1
  699. }
  700.  
  701. currentTrans += speed * speedMultiplier
  702.  
  703. SpeedMultiplier[host] = speedMultiplier
  704. CurrentTransparencyAmount[host] = currentTrans
  705. }
  706. else if(isFriend[host][ent])
  707. {
  708. set_es(es,ES_RenderMode,kRenderTransAlpha)
  709. set_es(es,ES_RenderAmt,CurrentTransparencyAmount[host])
  710. }
  711. }
  712. }
  713.  
  714. public steamToggle(id)
  715. {
  716. static printTo[] = {print_chat,print_console}
  717.  
  718. if(IsHighlightingFriends[id])
  719. {
  720. for(new i=0;i<sizeof printTo;i++)
  721. client_print(id,printTo[i],"%L",id,"HIGHLIGHT_STOP")
  722.  
  723. highlightFriendsStop(id)
  724. }
  725. else
  726. {
  727. for(new i=0;i<sizeof printTo;i++)
  728. client_print(id,printTo[i],"%L",id,"HIGHLIGHT_START")
  729.  
  730. highlightFriendsStart(id)
  731. }
  732.  
  733. return PLUGIN_HANDLED
  734. }