├── .github └── workflows │ └── smx-updater.yml ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── archive ├── plugins │ ├── FixHintColorMessages.smx │ ├── practicemode.smx │ ├── steambind.smx │ ├── utility_helper.smx │ └── utility_uploader.smx └── scripting │ ├── hltv.sp │ ├── mycity.sp │ ├── steambind.sp │ ├── utility_helper.sp │ └── utility_uploader.sp ├── plugins └── csgowiki-pack.smx └── scripting ├── csgowiki-pack.sp ├── csgowiki ├── kicker.sp ├── menus │ ├── menu_option.sp │ ├── menu_wiki.sp │ ├── menu_wikiop.sp │ └── menu_wikipro.sp ├── panel.sp ├── replay.sp ├── steam_bind.sp ├── utility_modify.sp ├── utility_submit.sp ├── utility_wiki.sp └── utils.sp └── include ├── botmimic_fix.inc └── csgowiki.inc /.github/workflows/smx-updater.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: smx-updater 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Allows you to run this workflow manually from the Actions tab 8 | push: 9 | branches: [ master ] 10 | workflow_dispatch: 11 | 12 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 13 | jobs: 14 | # This workflow contains a single job called "build" 15 | s1-dispatcher: 16 | # The type of runner that the job will run on 17 | runs-on: ubuntu-latest 18 | 19 | # Steps represent a sequence of tasks that will be executed as part of the job 20 | steps: 21 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 22 | - name: checkout-repo 23 | uses: actions/checkout@v2 24 | 25 | - name: dispatching 26 | uses: appleboy/scp-action@master 27 | with: 28 | host: s1.csgowiki.top 29 | username: csgo 30 | password: ${{ secrets.PASSWORD_S1 }} 31 | source: "plugins/*" 32 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" 33 | s2-dispatcher: 34 | # The type of runner that the job will run on 35 | runs-on: ubuntu-latest 36 | 37 | # Steps represent a sequence of tasks that will be executed as part of the job 38 | steps: 39 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 40 | - name: checkout-repo 41 | uses: actions/checkout@v2 42 | 43 | - name: dispatching 44 | uses: appleboy/scp-action@master 45 | with: 46 | host: s2.csgowiki.top 47 | username: csgo 48 | password: ${{ secrets.PASSWORD_S2 }} 49 | source: "plugins/*" 50 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" 51 | s3-dispatcher: 52 | # The type of runner that the job will run on 53 | runs-on: ubuntu-latest 54 | 55 | # Steps represent a sequence of tasks that will be executed as part of the job 56 | steps: 57 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 58 | - name: checkout-repo 59 | uses: actions/checkout@v2 60 | 61 | - name: dispatching 62 | uses: appleboy/scp-action@master 63 | with: 64 | host: s3.csgowiki.top 65 | username: csgo 66 | password: ${{ secrets.PASSWORD_S3 }} 67 | source: "plugins/*" 68 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" 69 | s4-dispatcher: 70 | # The type of runner that the job will run on 71 | runs-on: ubuntu-latest 72 | 73 | # Steps represent a sequence of tasks that will be executed as part of the job 74 | steps: 75 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 76 | - name: checkout-repo 77 | uses: actions/checkout@v2 78 | 79 | - name: dispatching 80 | uses: appleboy/scp-action@master 81 | with: 82 | host: s4.csgowiki.top 83 | username: csgo 84 | password: ${{ secrets.PASSWORD_S4 }} 85 | source: "plugins/*" 86 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" 87 | s5-dispatcher: 88 | # The type of runner that the job will run on 89 | runs-on: ubuntu-latest 90 | 91 | # Steps represent a sequence of tasks that will be executed as part of the job 92 | steps: 93 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 94 | - name: checkout-repo 95 | uses: actions/checkout@v2 96 | 97 | - name: dispatching 98 | uses: appleboy/scp-action@master 99 | with: 100 | host: s5.csgowiki.top 101 | username: csgo 102 | password: ${{ secrets.PASSWORD_S5 }} 103 | source: "plugins/*" 104 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" 105 | s6-dispatcher: 106 | # The type of runner that the job will run on 107 | runs-on: ubuntu-latest 108 | 109 | # Steps represent a sequence of tasks that will be executed as part of the job 110 | steps: 111 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 112 | - name: checkout-repo 113 | uses: actions/checkout@v2 114 | 115 | - name: dispatching 116 | uses: appleboy/scp-action@master 117 | with: 118 | host: s6.csgowiki.top 119 | username: csgo 120 | password: ${{ secrets.PASSWORD_S6 }} 121 | source: "plugins/*" 122 | target: "steamcmd/games/csgo/csgo/addons/sourcemod/" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.inc 3 | botreplay/ 4 | !csgowiki.inc 5 | !socket.inc 6 | !botmimic_fix.inc 7 | spcomp 8 | spcomp64 9 | compiled/ 10 | *.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 CarOL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub](https://img.shields.io/github/license/hx-w/CSGOWiki-Plugins) 2 | ![GitHub](https://img.shields.io/github/downloads/hx-w/CSGOWiki-Plugins/total) 3 | ![GitHub](https://img.shields.io/github/languages/top/hx-w/CSGOWiki-Plugins) 4 | ![smx-updater](https://github.com/hx-w/CSGOWiki-Plugins/workflows/smx-updater/badge.svg) 5 | 6 | # CSGOWiki-Pack 7 | `csgowiki-pack`插件服务于[csgowiki](https://mycsgolab.com)网站。 8 | 9 | 插件的正常运作需要csgowiki的账号,如果你没有,那么请先前往网站注册。 10 | 11 | 插件文档库请移步:[**csgowiki帮助中心**](https://docs.csgowiki.top/csgowiki-pack/index/) 12 | 13 | 文档库正在完善中。 14 | 15 | # Contributions | 贡献 16 | 17 | 如果你对本项目有一些想法,欢迎提交`issue`与我讨论。 18 | 19 | 欢迎提交pr。 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only >=v1.4.0 works. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 1.4.0+ | ✅ | 10 | | 1.3 | :x: | 11 | | 1.2.3 | :x: | 12 | | 1.2.2 | :x: | 13 | | < 1.2.2 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Open an issue if something works wrong. 18 | -------------------------------------------------------------------------------- /archive/plugins/FixHintColorMessages.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/archive/plugins/FixHintColorMessages.smx -------------------------------------------------------------------------------- /archive/plugins/practicemode.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/archive/plugins/practicemode.smx -------------------------------------------------------------------------------- /archive/plugins/steambind.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/archive/plugins/steambind.smx -------------------------------------------------------------------------------- /archive/plugins/utility_helper.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/archive/plugins/utility_helper.smx -------------------------------------------------------------------------------- /archive/plugins/utility_uploader.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/archive/plugins/utility_uploader.smx -------------------------------------------------------------------------------- /archive/scripting/hltv.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #pragma dynamic 50000 6 | 7 | #define STRLENGTH 32 8 | #define MATCHID 128 9 | #define RESULTSCACHE 10 10 | 11 | 12 | JSON_Object g_jResults[RESULTSCACHE]; 13 | bool g_bResultsQuery = false; 14 | 15 | public Plugin:myinfo = { 16 | name = "Htlv information", 17 | author = "CarOL", 18 | description = "show information grab from htlv", 19 | url = "https://github.com/Herixth/CSGOWiki-Plugins" 20 | }; 21 | 22 | public OnPluginStart() { 23 | RegConsoleCmd("sm_hltv", Command_Hltv); 24 | queryResults(); 25 | CreateTimer(120.0, TimerCallBack, _, TIMER_REPEAT); 26 | } 27 | 28 | public Action:Command_Hltv(client, args) { 29 | if (!g_bResultsQuery) { 30 | queryResults(); 31 | } 32 | setMainMenu(client); 33 | } 34 | 35 | void setMainMenu(client) { 36 | new Handle:menuhandle = CreateMenu(HltvMenuCallBack); 37 | SetMenuTitle(menuhandle, "Hltv信息面板"); 38 | AddMenuItem(menuhandle, "result", "比赛结果"); 39 | AddMenuItem(menuhandle, "news", "新闻(开发中...)"); 40 | AddMenuItem(menuhandle, "match", "比赛预告(开发中...)"); 41 | SetMenuPagination(menuhandle, 7); 42 | SetMenuExitButton(menuhandle, true); 43 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 44 | } 45 | 46 | void setSub1Menu(client) { 47 | new Handle:submenuhandle = CreateMenu(ResultMenuCallBack); 48 | SetMenuTitle(submenuhandle, "近期10场比赛结果"); 49 | for (int idx = 0; idx < RESULTSCACHE; idx ++) { 50 | char itemid[2]; 51 | char mapflg[8]; 52 | char teamname[2][STRLENGTH]; 53 | int results[2]; 54 | IntToString(idx, itemid, sizeof(itemid)); 55 | g_jResults[idx].GetString("maps", mapflg, sizeof(mapflg)); 56 | JSON_Object team1 = g_jResults[idx].GetObject("team1"); 57 | JSON_Object team2 = g_jResults[idx].GetObject("team2"); 58 | team1.GetString("name", teamname[0], STRLENGTH); 59 | team2.GetString("name", teamname[1], STRLENGTH); 60 | results[0] = team1.GetInt("result"); 61 | results[1] = team2.GetInt("result"); 62 | char showInfo[3 * STRLENGTH]; 63 | Format(showInfo, sizeof(showInfo), "[%d : %d] %s vs %s (%s)", results[0], results[1], teamname[0], teamname[1], mapflg); 64 | AddMenuItem(submenuhandle, itemid, showInfo); 65 | } 66 | SetMenuPagination(submenuhandle, 7); 67 | SetMenuExitBackButton(submenuhandle, true); 68 | SetMenuExitButton(submenuhandle, true); 69 | DisplayMenu(submenuhandle, client, MENU_TIME_FOREVER); 70 | } 71 | 72 | public HltvMenuCallBack(Handle:menuhandle, MenuAction:action, client, Position) { 73 | if (action == MenuAction_Select) { 74 | decl String:Item[STRLENGTH]; 75 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 76 | if (StrEqual(Item, "result")) { 77 | setSub1Menu(client); 78 | } 79 | } 80 | } 81 | 82 | public ResultMenuCallBack(Handle:menuhandle, MenuAction:action, client, Position) { 83 | if (action == MenuAction_Select) { 84 | decl String:Item[STRLENGTH]; 85 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 86 | int idx = StringToInt(Item); 87 | queryProRecord(client, idx); 88 | 89 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 90 | } 91 | if (Position == -6) { 92 | setMainMenu(client); 93 | } 94 | } 95 | 96 | void queryResults() { 97 | System2HTTPRequest httpRequest = new System2HTTPRequest( 98 | HltvApiResultCallBack, 99 | "https://hltv-api.vercel.app/api/results/" 100 | ) 101 | httpRequest.GET(); 102 | } 103 | 104 | void queryProRecord(client, int cachedIdx) { 105 | char matchId[MATCHID]; 106 | char event[64]; 107 | g_jResults[cachedIdx].GetString("matchId", matchId, sizeof(matchId)); 108 | g_jResults[cachedIdx].GetString("event", event, sizeof(event)); 109 | System2HTTPRequest httpRequest = new System2HTTPRequest( 110 | HltvApiProRecordCallBack, 111 | "https://hltv-api.vercel.app/api/%s/", 112 | matchId 113 | ) 114 | httpRequest.Any = client; 115 | httpRequest.GET(); 116 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x0E赛事\x01:---- \x03%s\x01 ----", event); 117 | } 118 | 119 | public HltvApiResultCallBack(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 120 | if (success) { 121 | char[] content = new char[response.ContentLength + 1]; 122 | response.GetContent(content, response.ContentLength + 1); 123 | JSONArray arr = view_as(json_decode(content)); 124 | for (int idx = 0; idx < RESULTSCACHE; idx++) { 125 | g_jResults[idx] = arr.GetObject(idx); 126 | } 127 | g_bResultsQuery = true; 128 | } 129 | else { 130 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02hltv-api访问失败,请及时联系服务器管理员"); 131 | } 132 | } 133 | 134 | public HltvApiProRecordCallBack(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 135 | int client = request.Any; 136 | if (success) { 137 | char[] content = new char[response.ContentLength + 1]; 138 | response.GetContent(content, response.ContentLength + 1); 139 | JSONArray proRecord = view_as(json_decode(content)); 140 | printOutProRecord(client, proRecord); 141 | } 142 | else { 143 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02hltv-api访问失败,请及时联系服务器管理员"); 144 | } 145 | } 146 | 147 | public Action:TimerCallBack(Handle timer) { 148 | queryResults(); 149 | } 150 | 151 | void printOutProRecord(client, JSONArray proRecord) { 152 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x01|\x0E 选手 \x01|\x09 击杀 \x01|\x09 死亡 \x01|\x09 ADR \x01|\x09 KAST \x01|\x10 Rating \x01|") 153 | for (int idx = 0; idx < 10; idx ++) { // 默认10人 可能有例外 154 | JSON_Object pro = proRecord.GetObject(idx); 155 | char oriName[STRLENGTH]; 156 | char NameBuffer[5][STRLENGTH]; 157 | pro.GetString("playerName", oriName, sizeof(oriName)); 158 | int kills = pro.GetInt("kills"); 159 | int deaths = pro.GetInt("deaths"); 160 | float adr = pro.GetFloat("adr"); 161 | float kast = pro.GetFloat("kast"); 162 | float rating = pro.GetFloat("rating"); 163 | ExplodeString(oriName, " ", NameBuffer, 5, STRLENGTH); 164 | if (rating >= 1) { 165 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x01|\x06 %8s \x01|\x0B %2d \x01|\x0B %2d \x01|\x08 %.1f \x01|\x08 %.1f \x01|\x04 %.2f \x01|", 166 | NameBuffer[1], kills, deaths, adr, kast, rating); 167 | } 168 | else { 169 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x01|\x06 %8s \x01|\x0B %2d \x01|\x0B %2d \x01|\x08 %.1f \x01|\x08 %.1f \x01|\x02 %.2f \x01|", 170 | NameBuffer[1], kills, deaths, adr, kast, rating); 171 | } 172 | } 173 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] ---------------------------------------------------"); 174 | } -------------------------------------------------------------------------------- /archive/scripting/mycity.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CLASSLENGTH 64 7 | #define RGBA 0, 255, 0, 255 8 | // https://www.nowapi.com/api/weather.today 在这里拿APPKEY和SIGN 9 | #define APPKEY "EMPTY" 10 | #define SIGN "EMPTY" 11 | 12 | Handle g_HTM; 13 | Handle g_hCookie_TabHud; 14 | bool g_bEnableTabHud[MAXPLAYERS + 1]; 15 | char g_sCity[MAXPLAYERS + 1][32]; 16 | char g_sWeek[MAXPLAYERS + 1][16]; 17 | char g_sWeather[MAXPLAYERS + 1][32]; 18 | char g_sTemp[MAXPLAYERS + 1][32]; 19 | char g_sTempNow[MAXPLAYERS + 1][16]; 20 | bool g_bChecked[MAXPLAYERS + 1]; 21 | 22 | public Plugin:myinfo = { 23 | name = "My city", 24 | author = "CarOL", 25 | description = "show something fun about my city(auto located)", 26 | url = "https://github.com/Herixth/CSGOWiki-Plugins" 27 | }; 28 | 29 | public OnPluginStart() { 30 | for (int idx = 0; idx <= MAXPLAYERS; idx++) { 31 | g_bChecked[idx] = false; 32 | } 33 | g_hCookie_TabHud = RegClientCookie("toggle_tabhud", "TabHud", CookieAccess_Protected); 34 | RegConsoleCmd("sm_tabhud", Command_ToggleTabHud); 35 | } 36 | 37 | public OnClientPutInServer(int client){ 38 | g_bEnableTabHud[client] = true; 39 | char buffer[CLASSLENGTH]; 40 | GetClientCookie(client, g_hCookie_TabHud, buffer, sizeof(buffer)); 41 | if(StrEqual(buffer, "0")){ 42 | g_bEnableTabHud[client] = false; 43 | } 44 | if (!g_bChecked[client] && IsValidClient(client)) { 45 | queryWeatherApi(client); 46 | g_bChecked[client] = true; 47 | } 48 | } 49 | 50 | public OnClientDisconnect(client) { 51 | g_bEnableTabHud[client] = false; 52 | } 53 | 54 | public Action:Command_ToggleTabHud(client, args) { 55 | if (g_bEnableTabHud[client]) { 56 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x04已关闭Tab页面显示天气等信息"); 57 | g_bEnableTabHud[client] = false; 58 | SetClientCookie(client, g_hCookie_TabHud, "0"); 59 | } 60 | else { 61 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x04已开启Tab页面显示天气等信息"); 62 | g_bEnableTabHud[client] = true; 63 | SetClientCookie(client, g_hCookie_TabHud, "1"); 64 | } 65 | return Plugin_Handled; 66 | } 67 | 68 | public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) { 69 | if (g_bEnableTabHud[client] && g_bChecked[client]) { 70 | if (buttons & IN_SCORE) { 71 | g_HTM = CreateHudSynchronizer(); 72 | char timeNow[CLASSLENGTH]; 73 | char showInfo[4 * CLASSLENGTH]; 74 | FormatTime(timeNow, sizeof(timeNow), "%H:%M:%S", GetTime()); 75 | Format(showInfo, sizeof(showInfo), "城市:%s \n天气:%s \n气温:%s(实时%s)\n时间:%s(%s) ", 76 | g_sCity[client], g_sWeather[client], g_sTemp[client], g_sTempNow[client], timeNow, g_sWeek[client]); 77 | SetHudTextParams(0.9, 0, 0.1, RGBA, 0, 0.1, 0.0, 10); 78 | ShowSyncHudText(client, g_HTM, showInfo); 79 | } 80 | } 81 | } 82 | 83 | void queryWeatherApi(client) { 84 | char c_IP[CLASSLENGTH]; 85 | GetClientIP(client, c_IP, sizeof(c_IP)); 86 | System2HTTPRequest httpRequest = new System2HTTPRequest( 87 | WeatherApiCallBack, 88 | "http://api.k780.com/?app=weather.today&weaid=%s&appkey=%s&sign=%s&format=json", 89 | c_IP, APPKEY, SIGN 90 | ) 91 | httpRequest.Any = client; 92 | httpRequest.GET(); 93 | } 94 | 95 | public void WeatherApiCallBack(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 96 | int client = request.Any; 97 | if (success) { 98 | char[] content = new char[response.ContentLength + 1]; 99 | char status[2]; 100 | response.GetContent(content, response.ContentLength + 1); 101 | JSON_Object json_obj = json_decode(content); 102 | json_obj.GetString("success", status, sizeof(status)); 103 | if (StrEqual(status, "1")) { 104 | JSON_Object res_obj = json_obj.GetObject("result"); 105 | res_obj.GetString("citynm", g_sCity[client], 32); 106 | res_obj.GetString("temperature", g_sTemp[client], 32); 107 | res_obj.GetString("temperature_curr", g_sTempNow[client], 16); 108 | res_obj.GetString("weather", g_sWeather[client], 32); 109 | res_obj.GetString("week", g_sWeek[client], 16); 110 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x04天气API请求成功"); 111 | } 112 | else { 113 | char errmsg[32]; 114 | json_obj.GetString("msg", errmsg, sizeof(errmsg)); 115 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02天气API请求失败: %s", errmsg); 116 | } 117 | } 118 | else { 119 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02api访问失败,请及时联系服务器管理员"); 120 | } 121 | } 122 | 123 | stock bool IsValidClient(int client) { 124 | return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); 125 | } 126 | -------------------------------------------------------------------------------- /archive/scripting/steambind.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CLASS_LENGTH 64 7 | #define INFO_LENGTH 16 8 | 9 | enum BindState { 10 | b_Unknown = 0, 11 | b_Unbind = 1, 12 | b_Binded = 2 13 | } 14 | 15 | new Handle:h_Enable = INVALID_HANDLE; 16 | 17 | BindState g_PlayerBindState[MAXPLAYERS + 1]; 18 | 19 | public Plugin:myinfo = { 20 | name = "Steam Bind Helper", 21 | author = "CarOL", 22 | description = "bind steamid from server to csgowiki.top", 23 | url = "csgowiki.top" 24 | }; 25 | 26 | public OnPluginStart() { 27 | RegConsoleCmd("sm_bsteam", Command_BindSteam); 28 | } 29 | 30 | public OnClientPutInServer(client) { 31 | if (IsPlayer(client)) { 32 | CreateTimer(3.0, QuerySteamTimerCallback, client); 33 | } 34 | } 35 | 36 | public OnClientDisconnect(client) { 37 | // reset bind_flag 38 | g_PlayerBindState[client] = b_Unknown; 39 | } 40 | 41 | public Action:QuerySteamTimerCallback(Handle timer, client) { 42 | queryWebSteamId(client); 43 | return Plugin_Handled; 44 | } 45 | 46 | public Action:Command_BindSteam(client, args) { 47 | if (args == 1) { 48 | char token[CLASS_LENGTH]; 49 | GetCmdArgString(token, sizeof(token)); 50 | TrimString(token); 51 | postBindInfo(client, token); 52 | } 53 | else { 54 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02请前往www.csgowiki.top获取steam绑定指令"); 55 | } 56 | } 57 | 58 | void queryWebSteamId(client) { 59 | char steamid[CLASS_LENGTH]; 60 | GetClientAuthId(client, AuthId_SteamID64, steamid, CLASS_LENGTH); 61 | // POST 62 | System2HTTPRequest httpRequest = new System2HTTPRequest( 63 | QuerySteamIdCallback, "https://www.csgowiki.top/api/server/steambind/?steamid=%s", steamid); 64 | httpRequest.Any = client; 65 | httpRequest.GET(); 66 | } 67 | 68 | 69 | void postBindInfo(client, char[] token) { 70 | char steamid[CLASS_LENGTH]; 71 | GetClientAuthId(client, AuthId_SteamID64, steamid, CLASS_LENGTH); 72 | System2HTTPRequest httpRequest = new System2HTTPRequest( 73 | SteamBindCallback, "https://www.csgowiki.top/api/server/steambind/"); 74 | httpRequest.SetData("steamid=%s&token=%s", steamid, token); 75 | httpRequest.Any = client; 76 | httpRequest.POST(); 77 | } 78 | 79 | public void QuerySteamIdCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 80 | int client = request.Any; 81 | if (success) { 82 | char[] content = new char[response.ContentLength + 1]; 83 | char[] status = new char[INFO_LENGTH]; 84 | char[] aliasname = new char[CLASS_LENGTH]; 85 | int client_level = 0; 86 | response.GetContent(content, response.ContentLength + 1); 87 | JSON_Object json_obj = json_decode(content); 88 | json_obj.GetString("status", status, INFO_LENGTH); 89 | if (StrEqual(status, "ok")) { 90 | json_obj.GetString("aliasname", aliasname, CLASS_LENGTH); 91 | client_level = json_obj.GetInt("level"); 92 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x09您已绑定网站账户: \x04%s\x01(\x05Lv%d\x01)", aliasname, client_level); 93 | g_PlayerBindState[client] = b_Binded; 94 | } 95 | else { 96 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02您还没有在csgowiki绑定steam账号~"); 97 | g_PlayerBindState[client] = b_Unbind; 98 | } 99 | } 100 | else { 101 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败"); 102 | } 103 | } 104 | 105 | public void SteamBindCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 106 | int client = request.Any; 107 | if (success) { 108 | char[] content = new char[response.ContentLength + 1]; 109 | char[] status = new char[INFO_LENGTH]; 110 | char[] aliasname = new char[CLASS_LENGTH]; 111 | int client_level = 0; 112 | response.GetContent(content, response.ContentLength + 1); 113 | JSON_Object json_obj = json_decode(content); 114 | json_obj.GetString("status", status, INFO_LENGTH); 115 | if (StrEqual(status, "ok")) { 116 | json_obj.GetString("aliasname", aliasname, CLASS_LENGTH); 117 | client_level = json_obj.GetInt("level"); 118 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x09账号绑定成功: \x04%s\x01(\x05Lv%d\x01)", aliasname, client_level); 119 | g_PlayerBindState[client] = b_Binded; 120 | } 121 | else { 122 | char[] message = new char[CLASS_LENGTH]; 123 | json_obj.GetString("message", message, CLASS_LENGTH); 124 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02%s", message); 125 | g_PlayerBindState[client] = b_Unbind; 126 | } 127 | } 128 | else { 129 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败"); 130 | } 131 | } 132 | 133 | stock bool IsPlayer(int client) { 134 | return IsValidClient(client) && !IsFakeClient(client) && !IsClientSourceTV(client); 135 | } 136 | 137 | stock bool IsValidClient(int client) { 138 | return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); 139 | } -------------------------------------------------------------------------------- /archive/scripting/utility_helper.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma dynamic 50000 8 | 9 | #define MAPNAME_MAXLENGTH 16 10 | #define STATUS_LENGTH 32 11 | #define ID_LENGTH 7 12 | #define BRIEF_LENGTH 50 13 | #define UTILITY_TYPE_LENGTH 36 14 | #define CLASS_LENGTH 16 15 | #define NAME_LENGTH 32 16 | #define COMMAND_LENGTH 64 17 | #define DIM 3 18 | 19 | char g_CurrentMap[MAPNAME_MAXLENGTH]; 20 | int g_ServerTickRate; 21 | JSONArray g_utilityCollection; 22 | JSONArray g_LastUtilityDetail[MAXPLAYERS + 1]; 23 | JSONArray g_utSearchResult[MAXPLAYERS + 1]; 24 | bool g_Collection_status = false; 25 | Handle wiki_timer = INVALID_HANDLE; 26 | Handle collect_timer = INVALID_HANDLE; 27 | bool is_on = true; // !enable/!disable 28 | 29 | new Handle:h_Enable = INVALID_HANDLE; 30 | 31 | public Plugin:myinfo = { 32 | name = "Utility Helper", 33 | author = "CarOL", 34 | description = "learn utilities from www.csgowiki.top", 35 | url = "www.csgowiki.top" 36 | }; 37 | 38 | public OnPluginStart() { 39 | RegConsoleCmd("sm_wiki", Command_Wiki); 40 | RegConsoleCmd("sm_last", Command_Last); 41 | RegConsoleCmd("sm_report", Command_Report); 42 | 43 | RegAdminCmd("sm_disable", Command_Disable_Wiki, ADMFLAG_GENERIC); 44 | RegAdminCmd("sm_enable", Command_Enable_Wiki, ADMFLAG_GENERIC); 45 | // RegAdminCmd("sm_modify", Command_Modify); 46 | 47 | // wiki_timer = CreateTimer(120.0, HelperTimerCallback, _, TIMER_REPEAT); 48 | g_ServerTickRate = RoundToZero(1.0 / GetTickInterval()); 49 | } 50 | 51 | public OnMapStart() { 52 | GetCurrentMap(g_CurrentMap, sizeof(g_CurrentMap)); 53 | for (int idx = 0; idx <= MAXPLAYERS; idx ++) 54 | g_utSearchResult[idx].Cleanup(); 55 | get_collection_from_server(); 56 | } 57 | 58 | public Action:Command_Wiki(client, args) { 59 | if (is_on == false) { 60 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale wiki 或只输入!enable (开启上传道具和学习道具两个插件)") 61 | return Plugin_Continue; 62 | } 63 | if (!g_Collection_status) { 64 | get_collection_from_server(); 65 | } 66 | if (g_Collection_status) { 67 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 输入\x06!last\x01查看上一次wiki学习的道具"); 68 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 输入\x06!report <内容>\x01反馈上一次道具中存在的问题"); 69 | show_menu_v1(client); 70 | } 71 | return Plugin_Continue; 72 | } 73 | 74 | public Action:Command_Last(client, args) { 75 | if (is_on == false) { 76 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale wiki 或只输入!enable (开启上传道具和学习道具两个插件)") 77 | return Plugin_Continue; 78 | } 79 | if (g_LastUtilityDetail[client].Length > 1) { 80 | show_utility_detail(client); 81 | } 82 | return Plugin_Continue; 83 | } 84 | 85 | public Action:Command_Report(client, args) { 86 | if (is_on == false) { 87 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale wiki 或只输入!enable (开启上传道具和学习道具两个插件)") 88 | return Plugin_Continue; 89 | } 90 | if (args >= 1) { 91 | if (g_LastUtilityDetail[client].Length > 1) { 92 | char t_report[BRIEF_LENGTH], ut_id[ID_LENGTH]; 93 | GetCmdArgString(t_report, BRIEF_LENGTH); 94 | TrimString(t_report); 95 | g_LastUtilityDetail[client].GetString(1, ut_id, ID_LENGTH); 96 | send_report_to_server(client, t_report, ut_id); 97 | } 98 | else { 99 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02没有找到历史记录,操作无效") 100 | } 101 | } 102 | else { 103 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02请输入!report <内容>") 104 | } 105 | return Plugin_Continue; 106 | } 107 | 108 | public Action:Command_Disable_Wiki(client, args) { 109 | if (args < 1 && is_on) { 110 | ServerCommand("sm_disable uploader"); 111 | ServerCommand("sm_disable wiki"); 112 | } 113 | if (args >= 1 && is_on) { 114 | char tarName[CLASS_LENGTH]; 115 | GetCmdArgString(tarName, sizeof(tarName)); 116 | TrimString(tarName); 117 | if (StrEqual(tarName, "wiki")) { 118 | CloseHandle(wiki_timer); 119 | CloseHandle(collect_timer); 120 | is_on = false; 121 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 道具学习插件已关闭"); 122 | } 123 | } 124 | return Plugin_Continue; 125 | } 126 | 127 | public Action:Command_Enable_Wiki(client, args) { 128 | if (args < 1 && !is_on) { 129 | ServerCommand("sm_enable uploader"); 130 | ServerCommand("sm_enable wiki"); 131 | } 132 | if (args >= 1 && !is_on) { 133 | char tarName[CLASS_LENGTH]; 134 | GetCmdArgString(tarName, sizeof(tarName)); 135 | TrimString(tarName); 136 | if (StrEqual(tarName, "wiki")) { 137 | wiki_timer = CreateTimer(120.0, HelperTimerCallback, _, TIMER_REPEAT); 138 | collect_timer = CreateTimer(600.0, UpdateCollectionTimerCallback, _, TIMER_REPEAT); 139 | is_on = true; 140 | get_collection_from_server(); 141 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 道具学习插件已开启"); 142 | } 143 | } 144 | return Plugin_Continue; 145 | } 146 | 147 | // public Action:Command_Modify(client, args) { 148 | // if (args < 1) { 149 | // PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 使用方法 \x04/modify "); 150 | // } 151 | // else { 152 | // if (g_LastUtilityDetail[client].Length > 1) { 153 | // char token[NAME_LENGTH + 1], ut_id[ID_LENGTH]; 154 | // GetCmdArgString(token, sizeof(token)); 155 | // TrimString(token); 156 | // g_LastUtilityDetail[client].GetString(1, ut_id, ID_LENGTH); 157 | // send_modify_to_server(client, token, ut_id); 158 | // // PrintToChat 159 | // } 160 | // else { 161 | // PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02没有找到缓存的道具记录"); 162 | // } 163 | // } 164 | // return Plugin_Continue; 165 | // } 166 | 167 | public Action:HelperTimerCallback(Handle timer) { 168 | show_help_info(); 169 | return Plugin_Continue; 170 | } 171 | 172 | public Action:UpdateCollectionTimerCallback(Handle timer) { 173 | get_collection_from_server(); 174 | return Plugin_Continue; 175 | } 176 | 177 | void decode_utility_type(char[] ut_type, int flg = 0, int client = 0) { 178 | if (StrEqual(ut_type, "smoke")) { 179 | if (flg == 0) { 180 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "[烟雾弹] "); 181 | } 182 | else if (flg == 1) { 183 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "烟雾弹"); 184 | } 185 | else if (flg == 2) { 186 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "weapon_smokegrenade"); 187 | } 188 | return; 189 | } 190 | else if (StrEqual(ut_type, "grenade")) { 191 | if (flg == 0) { 192 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "[手雷] "); 193 | } 194 | else if (flg == 1) { 195 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "手雷"); 196 | } 197 | else if (flg == 2) { 198 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "weapon_hegrenade"); 199 | } 200 | return; 201 | } 202 | else if (StrEqual(ut_type, "flash")) { 203 | if (flg == 0) { 204 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "[闪光弹] "); 205 | } 206 | else if (flg == 1) { 207 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "闪光弹"); 208 | } 209 | else if (flg == 2) { 210 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "weapon_flashbang"); 211 | } 212 | return; 213 | } 214 | else if (StrEqual(ut_type, "molotov")) { 215 | if (flg == 0) { 216 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "[燃烧弹] "); 217 | } 218 | else if (flg == 1) { 219 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "燃烧弹/燃烧瓶"); 220 | } 221 | else if (flg == 2) { 222 | int teamid = GetClientTeam(client); 223 | if (CS_TEAM_T == teamid) { 224 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "weapon_molotov"); 225 | } 226 | else if (CS_TEAM_CT == teamid) { 227 | strcopy(ut_type, UTILITY_TYPE_LENGTH, "weapon_incgrenade"); 228 | } 229 | } 230 | return; 231 | } 232 | } 233 | 234 | void show_help_info() { 235 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 输入\x06!wiki\x01查看道具列表"); 236 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 输入\x06!submit\x01上传道具至\x09www.csgowiki.top"); 237 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 输入\x02!knife\x01换刀型,输入\x02!glove\x01换手套,输入\x02!ws换皮肤\x01,仅供大家服内娱乐"); 238 | } 239 | 240 | void show_menu_v1(client) { 241 | new Handle:menuhandle = CreateMenu(MenuCallBack_v1); 242 | SetMenuTitle(menuhandle, "CSGO Wiki道具分类"); 243 | 244 | AddMenuItem(menuhandle, "smoke", "烟雾弹"); 245 | AddMenuItem(menuhandle, "flash", "闪光弹"); 246 | AddMenuItem(menuhandle, "grenade", "手雷"); 247 | AddMenuItem(menuhandle, "molotov", "燃烧弹/燃烧瓶"); 248 | 249 | AddMenuItem(menuhandle, "search_around_startspot", ">>查询附近起点道具<<"); 250 | AddMenuItem(menuhandle, "search_around_endspot", ">>查询附近落点道具<<"); 251 | 252 | SetMenuPagination(menuhandle, 7); 253 | SetMenuExitButton(menuhandle, true); 254 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 255 | } 256 | 257 | void show_menu_v2(client, char[] c_ut_type) { 258 | new Handle:menuhandle = CreateMenu(MenuCallBack_v2); 259 | SetMenuTitle(menuhandle, "CSGO Wiki道具合集(当前地图&Tick)"); 260 | int type_count = 0; 261 | for (int idx = 1; idx < g_utilityCollection.Length; idx ++) { 262 | if (g_utilityCollection.GetKeyType(idx) == JSON_Type_Object) { 263 | JSONArray arrval = view_as(g_utilityCollection.GetObject(idx)); 264 | char ut_id[ID_LENGTH], ut_brief[BRIEF_LENGTH], ut_type[UTILITY_TYPE_LENGTH]; 265 | arrval.GetString(0, ut_id, ID_LENGTH); 266 | arrval.GetString(1, ut_brief, BRIEF_LENGTH); 267 | arrval.GetString(2, ut_type, UTILITY_TYPE_LENGTH); 268 | if (StrEqual(ut_type, c_ut_type)) { 269 | decode_utility_type(ut_type); 270 | char msg[BRIEF_LENGTH + UTILITY_TYPE_LENGTH] = ""; 271 | StrCat(msg, sizeof(msg), ut_type); 272 | StrCat(msg, sizeof(msg), ut_brief); 273 | AddMenuItem(menuhandle, ut_id, msg); 274 | type_count ++; 275 | } 276 | } 277 | } 278 | if (type_count == 0) { 279 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x09未找到该种类道具"); 280 | show_menu_v1(client); 281 | return; 282 | } 283 | 284 | SetMenuPagination(menuhandle, 7); 285 | SetMenuExitBackButton(menuhandle, true); 286 | SetMenuExitButton(menuhandle, true); 287 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 288 | } 289 | 290 | void show_menu_v3(client) { 291 | if (g_utSearchResult[client].Length == 1) { 292 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x10你所在区域没有找到道具记录"); 293 | show_menu_v1(client); 294 | return; 295 | } 296 | new Handle:menuhandle = CreateMenu(MenuCallBack_v3); 297 | SetMenuTitle(menuhandle, "查询到的道具"); 298 | 299 | for (int idx = 1; idx < g_utSearchResult[client].Length; idx ++) { 300 | if (g_utSearchResult[client].GetKeyType(idx) == JSON_Type_Object) { 301 | JSONArray arrval = view_as(g_utSearchResult[client].GetObject(idx)); 302 | char ut_id[ID_LENGTH], ut_brief[BRIEF_LENGTH], ut_type[UTILITY_TYPE_LENGTH]; 303 | arrval.GetString(0, ut_id, ID_LENGTH); 304 | arrval.GetString(1, ut_brief, BRIEF_LENGTH); 305 | arrval.GetString(2, ut_type, UTILITY_TYPE_LENGTH); 306 | decode_utility_type(ut_type); 307 | char msg[BRIEF_LENGTH + UTILITY_TYPE_LENGTH] = ""; 308 | StrCat(msg, sizeof(msg), ut_type); 309 | StrCat(msg, sizeof(msg), ut_brief); 310 | AddMenuItem(menuhandle, ut_id, msg); 311 | } 312 | } 313 | SetMenuPagination(menuhandle, 7); 314 | SetMenuExitBackButton(menuhandle, true); 315 | SetMenuExitButton(menuhandle, true); 316 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 317 | } 318 | 319 | void show_utility_detail(client) { 320 | // response format: 321 | // [status, id:str, ut_type:str, ut_brief:str, ut_author_name:str, 322 | // ut_start_x, y, z, aim_pitch, aim_yaw, action:str, mouse_action:str] 323 | char ut_id[ID_LENGTH], ut_type[UTILITY_TYPE_LENGTH], ut_brief[BRIEF_LENGTH]; 324 | char author_name[NAME_LENGTH], ut_name[UTILITY_TYPE_LENGTH]; 325 | char bodyaction[CLASS_LENGTH], mouseaction[CLASS_LENGTH]; 326 | float originPosition[DIM], originAngle[DIM]; 327 | g_LastUtilityDetail[client].GetString(1, ut_id, ID_LENGTH); 328 | g_LastUtilityDetail[client].GetString(2, ut_type, UTILITY_TYPE_LENGTH); 329 | g_LastUtilityDetail[client].GetString(3, ut_brief, BRIEF_LENGTH); 330 | g_LastUtilityDetail[client].GetString(4, author_name, NAME_LENGTH); 331 | originPosition[0] = g_LastUtilityDetail[client].GetFloat(5); 332 | originPosition[1] = g_LastUtilityDetail[client].GetFloat(6); 333 | originPosition[2] = g_LastUtilityDetail[client].GetFloat(7); 334 | originAngle[0] = g_LastUtilityDetail[client].GetFloat(8); 335 | originAngle[1] = g_LastUtilityDetail[client].GetFloat(9); 336 | g_LastUtilityDetail[client].GetString(10, bodyaction, CLASS_LENGTH); 337 | g_LastUtilityDetail[client].GetString(11, mouseaction, CLASS_LENGTH); 338 | // decoding 339 | strcopy(ut_name, UTILITY_TYPE_LENGTH, ut_type); 340 | decode_utility_type(ut_type, 1); // flg = 1 341 | decode_utility_type(ut_name, 2, client); // flg = 2 342 | // tp client to aim point and give&force use client utility 343 | TeleportEntity(client, originPosition, originAngle, NULL_VECTOR); 344 | GivePlayerItem(client, ut_name); 345 | SetEntProp(client, Prop_Send, "m_iAmmo", 1); 346 | char clientcommand[COMMAND_LENGTH] = "use "; 347 | StrCat(clientcommand, COMMAND_LENGTH, ut_name); 348 | FakeClientCommand(client, clientcommand); 349 | // 350 | 351 | // print detail to client 352 | PrintToChat(client, "\x09 ------------------------------------- "); 353 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 道具ID: \x10%s", ut_id); 354 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 道具名称: \x10%s", ut_brief); 355 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 道具种类: \x10%s", ut_type); 356 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 提交人: \x10%s", author_name); 357 | PrintToChat(client, "\x09 ------------------------------------- "); 358 | // 359 | PrintCenterText(client, "身体动作:%s\n鼠标动作:%s\n", bodyaction, mouseaction); 360 | } 361 | 362 | void get_collection_from_server() { 363 | System2HTTPRequest httpRequest = new System2HTTPRequest(CollectionCallback, "https://www.csgowiki.top/api/utility/collection/"); 364 | httpRequest.SetData("map=%s&tickrate=%d", g_CurrentMap, g_ServerTickRate); 365 | httpRequest.POST(); 366 | } 367 | 368 | void get_detail_from_server(client, char[] ut_id) { 369 | System2HTTPRequest httpRequest = new System2HTTPRequest(DetailCallback, "https://www.csgowiki.top/api/utility/detail_info/"); 370 | httpRequest.SetData("id=%s", ut_id); 371 | httpRequest.Any = client; 372 | httpRequest.POST(); 373 | } 374 | 375 | void get_search_result(client, char[] flag) { 376 | // get pos 377 | float playerPos[3]; 378 | GetClientAbsOrigin(client, playerPos); 379 | System2HTTPRequest httpRequest = new System2HTTPRequest( 380 | SearchResultCallback, 381 | "https://www.csgowiki.top/api/utility/spot_filter/?map=%s&tickrate=%d&method=%s&x=%f&y=%f", 382 | g_CurrentMap, g_ServerTickRate, flag, playerPos[0], playerPos[1] 383 | ); 384 | httpRequest.Any = client; 385 | httpRequest.GET(); 386 | } 387 | 388 | void send_report_to_server(client, char[] report, char[] ut_id) { 389 | System2HTTPRequest httpRequest = new System2HTTPRequest(ReportCallback, "https://www.csgowiki.top/api/utility/report/"); 390 | char steamid[NAME_LENGTH]; 391 | GetClientAuthId(client, AuthId_SteamID64, steamid, NAME_LENGTH); 392 | httpRequest.SetData("steamid=%s&ut_id=%s&report=%s", steamid, ut_id, report); 393 | httpRequest.Any = client; 394 | httpRequest.POST(); 395 | } 396 | 397 | public MenuCallBack_v1(Handle:menuhandle, MenuAction:action, client, Position) { 398 | if (action == MenuAction_Select) { 399 | decl String:Item[BRIEF_LENGTH]; 400 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 401 | if (StrEqual(Item, "search_around_endspot")) { 402 | get_search_result(client, "end"); 403 | } 404 | else if (StrEqual(Item, "search_around_startspot")) { 405 | get_search_result(client, "start"); 406 | } 407 | else { 408 | show_menu_v2(client, Item); 409 | } 410 | } 411 | } 412 | 413 | public MenuCallBack_v2(Handle:menuhandle, MenuAction:action, client, Position) { 414 | if (action == MenuAction_Select) { 415 | decl String:Item[BRIEF_LENGTH]; 416 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 417 | 418 | for (int idx = 1; idx < g_utilityCollection.Length; idx ++) { 419 | if (g_utilityCollection.GetKeyType(idx) == JSON_Type_Object) { 420 | JSONArray arrval = view_as(g_utilityCollection.GetObject(idx)); 421 | char ut_id[ID_LENGTH]; 422 | arrval.GetString(0, ut_id, ID_LENGTH); 423 | if (StrEqual(ut_id, Item)) { 424 | get_detail_from_server(client, ut_id); 425 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 426 | } 427 | } 428 | } 429 | } 430 | if (Position == -6) { 431 | show_menu_v1(client); 432 | } 433 | } 434 | 435 | public MenuCallBack_v3(Handle:menuhandle, MenuAction:action, client, Position) { 436 | if (action == MenuAction_Select) { 437 | decl String:Item[BRIEF_LENGTH]; 438 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 439 | 440 | for (int idx = 1; idx < g_utSearchResult[client].Length; idx ++) { 441 | if (g_utSearchResult[client].GetKeyType(idx) == JSON_Type_Object) { 442 | JSONArray arrval = view_as(g_utSearchResult[client].GetObject(idx)); 443 | char ut_id[ID_LENGTH]; 444 | arrval.GetString(0, ut_id, ID_LENGTH); 445 | if (StrEqual(ut_id, Item)) { 446 | get_detail_from_server(client, ut_id); 447 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 448 | } 449 | } 450 | } 451 | } 452 | if (Position == -6) { 453 | show_menu_v1(client); 454 | } 455 | } 456 | 457 | public void ReportCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 458 | int client = request.Any; 459 | if (success) { 460 | char[] content = new char[response.ContentLength + 1]; 461 | response.GetContent(content, response.ContentLength + 1); 462 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] %s", content); 463 | } 464 | else { 465 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败"); 466 | } 467 | } 468 | 469 | public void DetailCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 470 | int client = request.Any; 471 | if (success) { 472 | char[] content = new char[response.ContentLength + 1]; 473 | char[] status = new char[STATUS_LENGTH]; 474 | response.GetContent(content, response.ContentLength + 1); 475 | 476 | g_LastUtilityDetail[client] = view_as(json_decode(content)); 477 | g_LastUtilityDetail[client].GetString(0, status, STATUS_LENGTH); 478 | if (StrEqual(status, "ok")) { 479 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x10获取道具信息成功,你将被传送至道具瞄点"); 480 | show_utility_detail(client); 481 | } 482 | else { 483 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02获取道具信息失败: %s", status); 484 | g_LastUtilityDetail[client].Cleanup(); 485 | } 486 | } 487 | else { 488 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败,无法获取道具详细信息"); 489 | } 490 | } 491 | 492 | public void CollectionCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 493 | if (success) { 494 | char[] content = new char[response.ContentLength + 1]; 495 | char[] status = new char[STATUS_LENGTH]; 496 | response.GetContent(content, response.ContentLength + 1); 497 | g_utilityCollection = view_as(json_decode(content)); 498 | g_utilityCollection.GetString(0, status, STATUS_LENGTH); 499 | if (StrEqual(status, "ok")) { 500 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x03已同步www.csgowiki.top道具合集"); 501 | g_Collection_status = true; 502 | } 503 | else { 504 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02同步道具合集失败"); 505 | g_utilityCollection.Cleanup(); 506 | g_Collection_status = false; 507 | } 508 | } 509 | else { 510 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败,无法同步道具集"); 511 | } 512 | } 513 | 514 | public void SearchResultCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 515 | if (success) { 516 | int client = request.Any; 517 | char[] content = new char[response.ContentLength + 1]; 518 | char[] status = new char[STATUS_LENGTH]; 519 | response.GetContent(content, response.ContentLength + 1); 520 | g_utSearchResult[client] = view_as(json_decode(content)); 521 | g_utSearchResult[client].GetString(0, status, STATUS_LENGTH); 522 | if (StrEqual(status, "ok")) { 523 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x03道具查询已完成"); 524 | show_menu_v3(client); 525 | } 526 | else { 527 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02道具查询失败,请联系csgowiki管理员"); 528 | g_utSearchResult[client].Cleanup(); 529 | } 530 | } 531 | else { 532 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败,无法同步道具集"); 533 | } 534 | } -------------------------------------------------------------------------------- /archive/scripting/utility_uploader.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define UTILITY_DIM 3 7 | #define ID_LENGTH 6 8 | #define ACTION_NUM 9 9 | #define WIKI_ACTION 7 10 | #define TINYTAG 10 11 | #define BRIEFLENGTH 30 12 | #define STEAMID64 20 13 | #define CLIENTARG_MAXLENGTH 16 14 | #define MAPNAME_MAXLENGTH 16 15 | #define NUMBASE 16 | #define CLASS_LENGTH 64 17 | #define MESSAGE_MAXLENGTH 256 18 | 19 | 20 | enum ClientStatus { 21 | s_Default = 0, 22 | s_ThrowReady = 1, 23 | s_ThrowEnd = 2, 24 | s_AlreadyThrown = 5, 25 | s_ButtonOn = 6 26 | }; 27 | 28 | enum UtilityEncode { 29 | u_Grenade = 0, 30 | u_Flashbang = 1, 31 | u_Smoke = 2, 32 | u_Molotov = 3, 33 | }; 34 | 35 | enum WikiAction { 36 | w_Jump = 0, 37 | w_Duck = 1, 38 | w_Run = 2, 39 | w_Walk = 3, 40 | w_Stand = 4, 41 | w_LeftClick = 5, 42 | w_RightClick = 6, 43 | }; 44 | 45 | new g_ActionList[ACTION_NUM] = { 46 | IN_JUMP, IN_DUCK, IN_ATTACK, IN_ATTACK2, IN_MOVELEFT, IN_MOVERIGHT, IN_FORWARD, IN_BACK, IN_SPEED 47 | } 48 | 49 | ClientStatus g_PlayerStatus[MAXPLAYERS + 1]; 50 | UtilityEncode g_UtilityName[MAXPLAYERS + 1]; 51 | char g_UtilityBrief[MAXPLAYERS + 1][BRIEFLENGTH]; 52 | float g_OriginPositions[MAXPLAYERS + 1][UTILITY_DIM]; 53 | float g_OriginAngles[MAXPLAYERS + 1][UTILITY_DIM]; // pitch yaw [-roll] 54 | float g_ThrowPositions[MAXPLAYERS + 1][UTILITY_DIM]; 55 | float g_EndspotPositions[MAXPLAYERS + 1][UTILITY_DIM]; 56 | int g_ActionRecord[MAXPLAYERS + 1]; 57 | char g_CurrentMap[MAPNAME_MAXLENGTH]; 58 | int g_ServerTickRate; // "64" "64/128" "128" 59 | char g_ClientLastCode[MAXPLAYERS + 1][ID_LENGTH]; 60 | float g_UtilityAirtime[MAXPLAYERS + 1]; 61 | char g_HistoryCode[MAXPLAYERS + 1][CLASS_LENGTH][ID_LENGTH]; 62 | char g_HistoryBrief[MAXPLAYERS + 1][CLASS_LENGTH][BRIEFLENGTH]; 63 | int g_PointerOfHistoryCode[MAXPLAYERS + 1]; 64 | bool g_InUse[MAXPLAYERS + 1]; 65 | Handle upload_timer = INVALID_HANDLE; 66 | bool is_on = true; 67 | 68 | new Hangle:h_Enable = INVALID_HANDLE; 69 | 70 | public Plugin:myinfo = { 71 | name = "Utility Uploader", 72 | author = "CarOL", 73 | description = "Upload utility record to www.csgowiki.top", 74 | url = "www.csgowiki.top" 75 | }; 76 | 77 | public OnPluginStart() { 78 | HookEvent("grenade_thrown", Event_GrenadeThrown); 79 | HookEvent("hegrenade_detonate", Event_HegrenadeDetonate); 80 | HookEvent("flashbang_detonate", Event_FlashbangDetonate); 81 | HookEvent("smokegrenade_detonate", Event_SmokeDetonate); 82 | HookEvent("molotov_detonate", Event_MolotovDetonate); 83 | // 捕捉道具路径 84 | HookEvent("grenade_bounce", Event_GrenadeBounce); 85 | 86 | RegConsoleCmd("sm_submit", Command_SubmitOn); 87 | RegConsoleCmd("sm_list", Command_ShowList); 88 | RegConsoleCmd("sm_tphere", Command_TeleportHere); 89 | RegConsoleCmd("sm_tp", Command_Teleport); 90 | 91 | RegAdminCmd("sm_disable", Command_Disable_Uploader, ADMFLAG_GENERIC); 92 | RegAdminCmd("sm_enable", Command_Enable_Uploader, ADMFLAG_GENERIC); 93 | 94 | // upload_timer = CreateTimer(120.0, HelperTimerCallback, _, TIMER_REPEAT); 95 | g_ServerTickRate = RoundToZero(1.0 / GetTickInterval()); 96 | } 97 | 98 | public OnMapStart() { 99 | GetCurrentMap(g_CurrentMap, MAPNAME_MAXLENGTH); 100 | // init 101 | for (new client = 0; client <= MAXPLAYERS; client++) { 102 | g_PlayerStatus[client] = s_Default; 103 | g_ActionRecord[client] = 0; 104 | g_UtilityBrief[client] = ""; 105 | } 106 | } 107 | 108 | public OnClientDisconnect(client) { 109 | g_PointerOfHistoryCode[client] = 0; 110 | } 111 | 112 | public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[UTILITY_DIM], Float:angles[UTILITY_DIM], &weapon) { 113 | if (is_on == false) 114 | return Plugin_Continue; 115 | 116 | if (g_PlayerStatus[client] == s_Default || g_PlayerStatus[client] == s_ButtonOn) { 117 | if (!g_InUse[client] && buttons & IN_USE) { 118 | g_InUse[client] = true; 119 | if (g_PlayerStatus[client] == s_Default) { 120 | g_PlayerStatus[client] = s_ButtonOn; 121 | CreateTimer(0.8, USETimerCallBack, client); 122 | } 123 | else if (g_PlayerStatus[client] == s_ButtonOn) { 124 | ClientCommand(client, "sm_submit"); 125 | } 126 | } 127 | else if (g_InUse[client] && !(buttons & IN_USE)) { 128 | g_InUse[client] = false; 129 | } 130 | } 131 | if (g_PlayerStatus[client] == s_ThrowReady) { 132 | for (new idx = 0; idx < ACTION_NUM; idx++) { 133 | if ((g_ActionList[idx] & buttons) && !(g_ActionRecord[client] & (1 << idx))) { 134 | g_ActionRecord[client] |= 1 << idx; 135 | } 136 | } 137 | } 138 | return Plugin_Continue; 139 | } 140 | 141 | public Action:USETimerCallBack(Handle timer, client) { 142 | if (g_PlayerStatus[client] == s_ButtonOn) { 143 | g_PlayerStatus[client] = s_Default; 144 | } 145 | } 146 | 147 | public Action:Event_GrenadeThrown(Handle:event, const String:name[], bool:dontBroadcast) { 148 | if (is_on == false) 149 | return Plugin_Continue; 150 | new String:nade[CLASS_LENGTH]; 151 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 152 | GetEventString(event, "weapon", nade, sizeof(nade)); 153 | if (g_PlayerStatus[client] == s_ThrowReady && !StrEqual(nade, "decoy") && IsPlayer(client)) { 154 | GetClientAbsOrigin(client, g_ThrowPositions[client]); 155 | g_UtilityAirtime[client] = GetEngineTime(); 156 | g_UtilityName[client] = encode_utility(nade); 157 | // next status 158 | g_PlayerStatus[client] = s_AlreadyThrown; 159 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x08已经成功记录你的动作,等待道具爆开..."); 160 | } 161 | return Plugin_Continue; 162 | } 163 | 164 | public Action:Event_HegrenadeDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 165 | if (is_on == false) 166 | return Plugin_Continue; 167 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 168 | if (g_PlayerStatus[client] == s_AlreadyThrown && g_UtilityName[client] == u_Grenade) { 169 | g_PlayerStatus[client] = s_ThrowEnd; 170 | g_UtilityAirtime[client] = GetEngineTime() - g_UtilityAirtime[client]; 171 | g_EndspotPositions[client][0] = GetEventFloat(event, "x"); 172 | g_EndspotPositions[client][1] = GetEventFloat(event, "y"); 173 | g_EndspotPositions[client][2] = GetEventFloat(event, "z"); 174 | send_to_server(client); 175 | } 176 | return Plugin_Continue; 177 | } 178 | 179 | public Action:Event_FlashbangDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 180 | if (is_on == false) 181 | return Plugin_Continue; 182 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 183 | if (g_PlayerStatus[client] == s_AlreadyThrown && g_UtilityName[client] == u_Flashbang) { 184 | g_PlayerStatus[client] = s_ThrowEnd; 185 | g_UtilityAirtime[client] = GetEngineTime() - g_UtilityAirtime[client]; 186 | g_EndspotPositions[client][0] = GetEventFloat(event, "x"); 187 | g_EndspotPositions[client][1] = GetEventFloat(event, "y"); 188 | g_EndspotPositions[client][2] = GetEventFloat(event, "z"); 189 | send_to_server(client); 190 | } 191 | return Plugin_Continue; 192 | } 193 | 194 | public Action:Event_SmokeDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 195 | if (is_on == false) 196 | return Plugin_Continue; 197 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 198 | if (g_PlayerStatus[client] == s_AlreadyThrown && g_UtilityName[client] == u_Smoke) { 199 | g_PlayerStatus[client] = s_ThrowEnd; 200 | g_UtilityAirtime[client] = GetEngineTime() - g_UtilityAirtime[client]; 201 | g_EndspotPositions[client][0] = GetEventFloat(event, "x"); 202 | g_EndspotPositions[client][1] = GetEventFloat(event, "y"); 203 | g_EndspotPositions[client][2] = GetEventFloat(event, "z"); 204 | send_to_server(client); 205 | } 206 | return Plugin_Continue; 207 | } 208 | 209 | public Action:Event_MolotovDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 210 | if (is_on == false) 211 | return Plugin_Continue; 212 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 213 | if (g_PlayerStatus[client] == s_AlreadyThrown && g_UtilityName[client] == u_Molotov) { 214 | g_PlayerStatus[client] = s_ThrowEnd; 215 | g_UtilityAirtime[client] = GetEngineTime() - g_UtilityAirtime[client]; 216 | g_EndspotPositions[client][0] = GetEventFloat(event, "x"); 217 | g_EndspotPositions[client][1] = GetEventFloat(event, "y"); 218 | g_EndspotPositions[client][2] = GetEventFloat(event, "z"); 219 | send_to_server(client); 220 | } 221 | return Plugin_Continue; 222 | } 223 | 224 | public Action:Event_GrenadeBounce(Handle:event, const String:name[], bool:dontBroadcast) { 225 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 226 | if (g_PlayerStatus[client] == s_AlreadyThrown) { 227 | 228 | } 229 | } 230 | 231 | public Action:Command_SubmitOn(client, args) { 232 | if (is_on == false) { 233 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale uploader 或只输入!enable (开启上传道具和学习道具两个插件)") 234 | return Plugin_Continue; 235 | } 236 | if (g_PlayerStatus[client] != s_Default && g_PlayerStatus[client] != s_ButtonOn) { 237 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02操作无效:尚未获取道具信息"); 238 | } 239 | else { 240 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x04道具上传功能开启"); 241 | GetClientAbsOrigin(client, g_OriginPositions[client]); 242 | GetClientEyeAngles(client, g_OriginAngles[client]); 243 | if (args >= 1) { 244 | GetCmdArgString(g_UtilityBrief[client], BRIEFLENGTH); 245 | TrimString(g_UtilityBrief[client]); 246 | PrintToChat(client, "\x01[\x05CSGO Wiki\01] 正在录制<\x0E%s\x01>", g_UtilityBrief[client]); 247 | } 248 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 您接下来投掷的道具记录将会被自动上传至\x09www.csgowiki.top\x01"); 249 | g_PlayerStatus[client] = s_ThrowReady; 250 | } 251 | return Plugin_Continue; 252 | } 253 | 254 | public Action:Command_TeleportHere(client, args) { 255 | if (is_on == false) { 256 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale uploader 或只输入!enable (开启上传道具和学习道具两个插件)") 257 | return Plugin_Continue; 258 | } 259 | if (args < 1) { 260 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02格式错误\x01:!tphere <玩家姓名> 支持正则表达式"); 261 | return Plugin_Continue; 262 | } 263 | char clientName[CLASS_LENGTH]; 264 | char tarName[CLASS_LENGTH]; 265 | float OriginPosition[UTILITY_DIM]; 266 | float OriginAngle[UTILITY_DIM]; 267 | GetClientName(client, clientName, sizeof(clientName)); 268 | GetCmdArgString(tarName, sizeof(tarName)); 269 | TrimString(tarName); 270 | GetClientAbsOrigin(client, OriginPosition); 271 | GetClientEyeAngles(client, OriginAngle); 272 | Regex regex = new Regex(tarName); 273 | int counter = 0; 274 | for (new t_client = 0; t_client <= MAXPLAYERS; t_client++) { 275 | if (t_client != client && IsPlayer(t_client)) { 276 | char t_name[CLASS_LENGTH]; 277 | GetClientName(t_client, t_name, sizeof(t_name)); 278 | if (regex.Match(t_name) > 0) { 279 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 已经将\x06%s\x01传送至\x03%s", t_name, clientName); 280 | TeleportEntity(t_client, OriginPosition, OriginAngle, NULL_VECTOR); 281 | counter++; 282 | } 283 | } 284 | } 285 | if (counter == 0) { 286 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 没有匹配到玩家,无人被传送") 287 | } 288 | return Plugin_Continue; 289 | } 290 | 291 | public Action:Command_Teleport(client, args) { 292 | if (is_on == false) { 293 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale uploader 或只输入!enable (开启上传道具和学习道具两个插件)") 294 | return Plugin_Continue; 295 | } 296 | if (args < 1) { 297 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02格式错误\x01:!tp <玩家姓名> 支持正则表达式(第一个匹配到的)"); 298 | return Plugin_Continue; 299 | } 300 | char clientName[CLASS_LENGTH]; 301 | char tarName[CLASS_LENGTH]; 302 | float OriginPosition[UTILITY_DIM]; 303 | float OriginAngle[UTILITY_DIM]; 304 | GetClientName(client, clientName, sizeof(clientName)); 305 | GetCmdArgString(tarName, sizeof(tarName)); 306 | TrimString(tarName); 307 | Regex regex = new Regex(tarName); 308 | int counter = 0; 309 | for (new t_client = 0; t_client <= MAXPLAYERS && counter == 0; t_client++) { 310 | if (t_client != client && IsPlayer(t_client)) { 311 | char t_name[CLASS_LENGTH]; 312 | GetClientName(t_client, t_name, sizeof(t_name)); 313 | if (regex.Match(t_name) > 0) { 314 | GetClientEyePosition(t_client, OriginPosition); 315 | GetClientEyeAngles(t_client, OriginAngle); 316 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 已经将\x06%s\x01传送至\x03%s", clientName, t_name); 317 | TeleportEntity(client, OriginPosition, OriginAngle, NULL_VECTOR); 318 | counter++; 319 | } 320 | } 321 | } 322 | if (counter == 0) { 323 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 没有匹配到玩家,未被传送") 324 | } 325 | return Plugin_Continue; 326 | } 327 | 328 | public Action:Command_ShowList(client, args) { 329 | if (is_on == false) { 330 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02插件已关闭,请输入!enbale uploader 或只输入!enable (开启上传道具和学习道具两个插件)") 331 | return Plugin_Continue; 332 | } 333 | PrintToChat(client, "\x09 ------------------------------------- "); 334 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] |\x03 道具名称 \x01|\x03 道具代码 \x01|"); 335 | for (int pointer = 0; pointer < g_PointerOfHistoryCode[client]; pointer++) { 336 | if (strlen(g_UtilityBrief[client]) > 0) { 337 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] |\x04 %s \x01|\x04 %s \x01|", g_HistoryBrief[client][pointer], g_HistoryCode[client][pointer]); 338 | } 339 | else { 340 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] |\x04 空 \x01|\x04 %s \x01|", g_HistoryCode[client][pointer]); 341 | } 342 | } 343 | PrintToChat(client, "\x09 ------------------------------------- "); 344 | return Plugin_Continue; 345 | } 346 | 347 | public Action:Command_Disable_Uploader(client, args) { 348 | if (args < 1 && is_on) { 349 | ServerCommand("sm_disable uploader"); 350 | ServerCommand("sm_disable wiki"); 351 | } 352 | if (args >= 1 && is_on) { 353 | char tarName[CLASS_LENGTH]; 354 | GetCmdArgString(tarName, sizeof(tarName)); 355 | TrimString(tarName); 356 | if (StrEqual(tarName, "uploader")) { 357 | CloseHandle(upload_timer); 358 | is_on = false; 359 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 道具上传插件已关闭"); 360 | } 361 | } 362 | } 363 | 364 | public Action:Command_Enable_Uploader(client, args) { 365 | if (args < 1 && !is_on) { 366 | ServerCommand("sm_enable uploader"); 367 | ServerCommand("sm_enable wiki"); 368 | } 369 | if (args >= 1 && !is_on) { 370 | char tarName[CLASS_LENGTH]; 371 | GetCmdArgString(tarName, sizeof(tarName)); 372 | TrimString(tarName); 373 | if (StrEqual(tarName, "uploader")) { 374 | upload_timer = CreateTimer(120.0, HelperTimerCallback, _, TIMER_REPEAT); 375 | is_on = true; 376 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] 道具上传插件已开启"); 377 | } 378 | } 379 | } 380 | 381 | void decode_action(int client, bool[WIKI_ACTION] actions) { 382 | for (new idx = 0; idx < ACTION_NUM; idx ++) { 383 | if ((g_ActionRecord[client] & (1 << idx))) { 384 | switch(g_ActionList[idx]) { 385 | case IN_JUMP: 386 | actions[w_Jump] = true; 387 | case IN_DUCK: 388 | actions[w_Duck] = true; 389 | case IN_ATTACK: 390 | actions[w_LeftClick] = true; 391 | case IN_ATTACK2: 392 | actions[w_RightClick] = true; 393 | case IN_MOVELEFT: 394 | actions[w_Run] = true; 395 | case IN_MOVERIGHT: 396 | actions[w_Run] = true; 397 | case IN_BACK: 398 | actions[w_Run] = true; 399 | case IN_FORWARD: 400 | actions[w_Run] = true; 401 | case IN_SPEED: 402 | actions[w_Walk] = true; 403 | } 404 | } 405 | } 406 | // postprocess 407 | if (!actions[w_Run] && actions[w_Walk]) { 408 | actions[w_Walk] = false; 409 | } 410 | if (actions[w_Run] && actions[w_Walk]) { 411 | actions[w_Run] = false; 412 | } 413 | if (actions[w_Run] && actions[w_Duck]) { 414 | actions[w_Walk] = true; 415 | actions[w_Run] = false; 416 | } 417 | if (!(actions[w_Run] || actions[w_Walk] || actions[w_Jump] || actions[w_Duck])) { 418 | actions[w_Stand] = true; 419 | } 420 | } 421 | 422 | void showInChat(int client) { 423 | bool actions[WIKI_ACTION]; 424 | char actionMessage[CLASS_LENGTH]; 425 | decode_action(client, actions); 426 | 427 | for (new idx = 0; idx < WIKI_ACTION; idx ++) { 428 | if (actions[idx]) { 429 | switch(idx) { 430 | case w_Jump: 431 | StrCat(actionMessage, sizeof(actionMessage), "跳 ") 432 | case w_Duck: 433 | StrCat(actionMessage, sizeof(actionMessage),"蹲 ") 434 | case w_Run: 435 | StrCat(actionMessage, sizeof(actionMessage), "跑 ") 436 | case w_Walk: 437 | StrCat(actionMessage, sizeof(actionMessage), "走 ") 438 | case w_Stand: 439 | StrCat(actionMessage, sizeof(actionMessage), "站 ") 440 | case w_LeftClick: 441 | StrCat(actionMessage, sizeof(actionMessage), "左键 ") 442 | case w_RightClick: 443 | StrCat(actionMessage, sizeof(actionMessage), "右键 ") 444 | } 445 | } 446 | } 447 | 448 | PrintToChat(client, "\x09 ------------------------------------- "); 449 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x04道具分析结果:"); 450 | if (strlen(g_UtilityBrief[client]) > 0) { 451 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06道具名称\x01 <\x0E%s\x01>", g_UtilityBrief[client]); 452 | } 453 | else { 454 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06道具名称\x01 <\x0E空\x01>", g_UtilityBrief[client]); 455 | } 456 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06起点\x01 %f,%f,%f", g_OriginPositions[client][0], g_OriginPositions[client][1], g_OriginPositions[client][2]); 457 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06角度\x01 %f,%f,%f", g_OriginAngles[client][0], g_OriginAngles[client][1], g_OriginAngles[client][2]); 458 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06出手点\x01 %f,%f,%f", g_ThrowPositions[client][0], g_ThrowPositions[client][1], g_ThrowPositions[client][2]); 459 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06落点\x01 %f,%f,%f", g_EndspotPositions[client][0], g_EndspotPositions[client][1], g_EndspotPositions[client][2]); 460 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06道具飞行时间\x01 %f", g_UtilityAirtime[client]); 461 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06动作列表\x01 %s", actionMessage); 462 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06当前地图\x01 %s", g_CurrentMap); 463 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x06当前tickrate\x01 %d", g_ServerTickRate); 464 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 服务器已将道具记录上传至\x09www.csgowiki.top\x01"); 465 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 该道具记录的短期标识为\x04%s\x01", g_ClientLastCode[client]); 466 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] 请在\x0224h\x01内登陆网站补全信息(图片和文字描述)"); 467 | PrintToChat(client, "\x09 ------------------------------------- "); 468 | 469 | } 470 | 471 | /** 472 | * steamid: char[STEAMID64] 473 | * start_x: float, start_y: float, start_z, float 474 | * end_x: float, end_y: float, end_z: float 475 | * throw_x y z 476 | * aim_pitch: float, aim_yaw: float 477 | * is_run, is_walk, is_jump, is_duck, is_left, is_right:bool [is_stand?] 478 | * map_belong: char[] 479 | * tick_tag: char[] 480 | * utility_tag: char[] 481 | * brief: char[] 482 | */ 483 | bool send_to_server(client) { 484 | char steamid[STEAMID64]; 485 | char utility_tag[TINYTAG]; 486 | char tick_tag[TINYTAG]; 487 | bool actions[WIKI_ACTION]; 488 | decode_utility(g_UtilityName[client], utility_tag); 489 | decode_action(client, actions); 490 | generate_ticktag(tick_tag, actions); 491 | GetClientAuthId(client, AuthId_SteamID64, steamid, STEAMID64); 492 | 493 | System2HTTPRequest httpRequest = new System2HTTPRequest(HttpResponseCallback, "https://www.csgowiki.top/api/utility/submit/"); 494 | httpRequest.SetData( 495 | "steamid=%s&start_x=%f&start_y=%f&start_z=%f&end_x=%f&end_y=%f&end_z=%f&aim_pitch=%f&aim_yaw=%f&is_run=%d&is_walk=%d&is_jump=%d&is_duck=%d&is_left=%d&is_right=%d&map_belong=%s&tickrate=%s&utility_type=%s&brief=%s&throw_x=%f&throw_y=%f&throw_z=%f&air_time=%f", 496 | steamid, g_OriginPositions[client][0], g_OriginPositions[client][1], 497 | g_OriginPositions[client][2], g_EndspotPositions[client][0], g_EndspotPositions[client][1], 498 | g_EndspotPositions[client][2], g_OriginAngles[client][0], g_OriginAngles[client][1], 499 | actions[w_Run], actions[w_Walk], actions[w_Jump], actions[w_Duck], actions[w_LeftClick], actions[w_RightClick], 500 | g_CurrentMap, tick_tag, utility_tag, g_UtilityBrief[client], 501 | g_ThrowPositions[client][0], g_ThrowPositions[client][1], g_ThrowPositions[client][2], 502 | g_UtilityAirtime[client] 503 | ); 504 | httpRequest.Any = client; 505 | httpRequest.POST(); 506 | return true; 507 | } 508 | 509 | generate_ticktag(char[] tick_tag, const bool[] actions) { 510 | StrCat(tick_tag, TINYTAG, "64/128"); 511 | for (int idx = 0; idx < WIKI_ACTION; idx ++) { 512 | if (actions[idx] && idx == w_Jump) { 513 | IntToString(g_ServerTickRate, tick_tag, TINYTAG); 514 | } 515 | } 516 | } 517 | 518 | void decode_utility(UtilityEncode uecode, char[] utility_tag) { 519 | switch (uecode) { 520 | case u_Grenade: 521 | StrCat(utility_tag, TINYTAG, "grenade"); 522 | case u_Flashbang: 523 | StrCat(utility_tag, TINYTAG, "flash"); 524 | case u_Smoke: 525 | StrCat(utility_tag, TINYTAG, "smoke"); 526 | case u_Molotov: 527 | StrCat(utility_tag, TINYTAG, "molotov"); 528 | } 529 | } 530 | 531 | UtilityEncode encode_utility(const char[] utilityName) { 532 | if (StrEqual(utilityName, "hegrenade")) { 533 | return u_Grenade; 534 | } 535 | else if (StrEqual(utilityName, "flashbang")) { 536 | return u_Flashbang; 537 | } 538 | else if (StrEqual(utilityName, "smokegrenade")) { 539 | return u_Smoke; 540 | } 541 | else { 542 | return u_Molotov; 543 | } 544 | } 545 | 546 | public void HttpResponseCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 547 | int client = request.Any; 548 | if (success) { 549 | char[] content = new char[response.ContentLength + 1]; 550 | response.GetContent(content, response.ContentLength + 1); 551 | int code_index = StrContains(content, "code"); 552 | for (new idx = 0; idx < ID_LENGTH; idx ++) { 553 | g_ClientLastCode[client][idx] = content[code_index + 8 + idx]; 554 | g_HistoryCode[client][g_PointerOfHistoryCode[client]][idx] = content[code_index + 8 + idx]; 555 | } 556 | strcopy(g_HistoryBrief[client][g_PointerOfHistoryCode[client]], BRIEFLENGTH, g_UtilityBrief[client]); 557 | g_PointerOfHistoryCode[client] ++; 558 | if (g_PointerOfHistoryCode[client] == CLASS_LENGTH) 559 | g_PointerOfHistoryCode[client] --; 560 | showInChat(client); 561 | } 562 | else { 563 | PrintToChat(client, "\x01[\x05CSGO Wiki\x01] \x02连接至www.csgowiki.top失败\x01,请反馈情况至\x09feedback@csgowiki.top"); 564 | } 565 | g_PlayerStatus[client] = s_Default; 566 | g_ActionRecord[client] = 0; 567 | g_UtilityBrief[client] = ""; 568 | } 569 | 570 | public Action:HelperTimerCallback(Handle timer) { 571 | PrintToChatAll("\x01[\x05CSGO Wiki\x01] \x02准备上传道具时,请先确保准星已经瞄好瞄点,再输入!submit"); 572 | return Plugin_Continue; 573 | } 574 | 575 | stock bool IsPlayer(int client) { 576 | return IsValidClient(client) && !IsFakeClient(client) && !IsClientSourceTV(client); 577 | } 578 | 579 | stock bool IsValidClient(int client) { 580 | return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); 581 | } 582 | -------------------------------------------------------------------------------- /plugins/csgowiki-pack.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/csgowiki/csgowiki-pack/147e72c83a8a442349c674f6e7d6b9ecaf534ec2/plugins/csgowiki-pack.smx -------------------------------------------------------------------------------- /scripting/csgowiki-pack.sp: -------------------------------------------------------------------------------- 1 | // 2 | #include 3 | 4 | #include "csgowiki/utils.sp" 5 | #include "csgowiki/panel.sp" 6 | 7 | #include "csgowiki/steam_bind.sp" 8 | #include "csgowiki/utility_submit.sp" 9 | #include "csgowiki/utility_wiki.sp" 10 | #include "csgowiki/utility_modify.sp" 11 | #include "csgowiki/kicker.sp" 12 | #include "csgowiki/replay.sp" 13 | 14 | 15 | public Plugin:myinfo = { 16 | name = "[CSGOWiki] Plugin-Pack", 17 | author = "CarOL", 18 | description = "An Sourcemod Instance For [CSGOWiki-Web] Service", 19 | version = "v1.4.3", 20 | url = "https://docs.csgowiki.top/plugins" 21 | }; 22 | 23 | public OnPluginStart() { 24 | // event 25 | HookEvent("hegrenade_detonate", Event_HegrenadeDetonate); 26 | HookEvent("flashbang_detonate", Event_FlashbangDetonate); 27 | HookEvent("smokegrenade_detonate", Event_SmokegrenadeDetonate); 28 | HookEvent("molotov_detonate", Event_MolotovDetonate); 29 | 30 | // command define 31 | // RegConsoleCmd("sm_bsteam", Command_BindSteam); 32 | RegAdminCmd("sm_srec", Command_Record, ADMFLAG_CHEATS); 33 | RegAdminCmd("sm_frec", Command_StopRecord, ADMFLAG_CHEATS); 34 | 35 | RegConsoleCmd("sm_submit", Command_Submit); 36 | RegConsoleCmd("sm_wiki", Command_Wiki); 37 | RegConsoleCmd("sm_abort", Command_SubmitAbort); 38 | 39 | RegConsoleCmd("sm_m", Command_Panel); 40 | 41 | RegConsoleCmd("sm_option", Command_Option); 42 | RegConsoleCmd("sm_wikipro", Command_WikiPro); 43 | 44 | RegConsoleCmd("sm_refresh", Command_Refresh); 45 | 46 | RegAdminCmd("sm_modify", Command_Modify, ADMFLAG_CHEATS); 47 | RegAdminCmd("sm_wikiop", Command_Wikiop, ADMFLAG_CHEATS); 48 | RegAdminCmd("sm_vel", Command_Velocity, ADMFLAG_GENERIC); 49 | 50 | // post fix 51 | g_iServerTickrate = GetServerTickrate(); 52 | 53 | HintColorMessageFixStart(); 54 | 55 | // convar 56 | g_hWikiAutoKicker = FindOrCreateConvar("sm_wiki_auto_kick", "0", "Set how long(min) can the player stay in server without binding csgowiki account. Set 0 to disable this kicker", 0.0, 10.0); 57 | g_hCSGOWikiEnable = FindOrCreateConvar("sm_csgowiki_enable", "0", "Set wether enable csgowiki plugins or not. Set 0 will disable all modules belong to CSGOWiki."); 58 | g_hOnUtilitySubmit = FindOrCreateConvar("sm_utility_submit_on", "1", "Set module: on/off."); 59 | g_hOnUtilityWiki = FindOrCreateConvar("sm_utility_wiki_on", "1", "Set module: on/off."); 60 | g_hCSGOWikiToken = FindOrCreateConvar("sm_csgowiki_token", "", "Make sure csgowiki token valid. Some modules will be disabled if csgowiki token invalid", -1.0, -1.0, true); 61 | g_hWikiReqLimit = FindOrCreateConvar("sm_wiki_request_limit", "1", "Limit cooling time(second) for each player's `!wiki` request. Set 0 to unlimit", 0.0, 10.0); 62 | g_hApiHost = FindOrCreateConvar("sm_csgowiki_apihost", "https://apiproxy.mycsgolab.com:5555", "Alternative option for this setting is `https://api.mycsgolab.com` which source in Hongkong"); 63 | 64 | HookOpConVarChange(); 65 | 66 | AutoExecConfig(true, "csgowiki-pack"); 67 | } 68 | 69 | public OnPluginEnd() { 70 | } 71 | 72 | public void OnLibraryAdded(const char[] name) { 73 | g_bBotMimicLoaded = LibraryExists("botmimic_fix"); 74 | } 75 | 76 | public void OnLibraryRemoved(const char[] name) { 77 | g_bBotMimicLoaded = LibraryExists("botmimic_fix"); 78 | } 79 | 80 | public OnMapStart() { 81 | g_iServerTickrate = GetServerTickrate(); 82 | GetCurrentMap(g_sCurrentMap, LENGTH_MAPNAME); 83 | 84 | // reset for map start 85 | ResetUtilitySubmitState(); 86 | ResetUtilityWikiState(); 87 | ResetReqLock(); 88 | 89 | // init collection 90 | GetAllCollection(); 91 | 92 | EnforceDirExists("data/csgowiki"); 93 | EnforceDirExists("data/csgowiki/replays"); 94 | EnforceDirExists("data/csgowiki/path"); 95 | } 96 | 97 | public OnMapEnd() { 98 | // delete g_aProMatchInfo; 99 | } 100 | 101 | public OnConfigsExecuted() { 102 | PluginVersionCheck(); 103 | } 104 | 105 | public OnClientPutInServer(client) { 106 | // timer define 107 | if (IsPlayer(client) && GetConVarBool(g_hCSGOWikiEnable)) { 108 | CreateTimer(3.0, QuerySteamTimerCallback, client); 109 | } 110 | ResetSingleClientWikiState(client); 111 | ResetSingleClientSubmitState(client); 112 | ClearPlayerToken(client); 113 | ResetReqLock(client); 114 | ClearPlayerProMatchInfo(client); 115 | ResetDefaultOption(client); 116 | } 117 | 118 | public OnClientDisconnect(client) { 119 | ResetSingleClientWikiState(client); 120 | ResetSingleClientSubmitState(client); 121 | ClearPlayerToken(client); 122 | ResetReqLock(client); 123 | // reset bind_flag 124 | ResetSteamBindFlag(client); 125 | ClearPlayerProMatchInfo(client); 126 | ResetDefaultOption(client); 127 | } 128 | 129 | public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[DATA_DIM], Float:angles[DATA_DIM], &weapon) { 130 | // for utility submit 131 | // if (!buttons) return; 132 | if (GetConVarBool(g_hOnUtilitySubmit)) { 133 | OnPlayerRunCmdForUtilitySubmit(client, buttons); 134 | } 135 | } 136 | 137 | public Action:Event_HegrenadeDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 138 | if (GetConVarBool(g_hOnUtilitySubmit)) { 139 | Event_HegrenadeDetonateForUtilitySubmit(event); 140 | } 141 | } 142 | 143 | public Action:Event_FlashbangDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 144 | if (GetConVarBool(g_hOnUtilitySubmit)) { 145 | Event_FlashbangDetonateForUtilitySubmit(event); 146 | } 147 | } 148 | 149 | public Action:Event_SmokegrenadeDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 150 | if (GetConVarBool(g_hOnUtilitySubmit)) { 151 | Event_SmokegrenadeDetonateForUtilitySubmit(event); 152 | } 153 | } 154 | 155 | 156 | public Action:Event_MolotovDetonate(Handle:event, const String:name[], bool:dontBroadcast) { 157 | if (GetConVarBool(g_hOnUtilitySubmit)) { 158 | Event_MolotovDetonateForUtilitySubmit(event); 159 | } 160 | } 161 | 162 | public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { 163 | if (!IsPlayer(client)) { 164 | return Plugin_Continue; 165 | } 166 | 167 | if (GetConVarFloat(g_hWikiAutoKicker) != 0.0) { 168 | if (g_aPlayerStateBind[client] == e_bUnbind) { 169 | PrintToChat(client, "%s \x02请前往mycsgolab.com绑定steam账号,有疑问请加群:762993431", PREFIX); 170 | PrintCenterText(client, "\x02请前往mycsgolab.com绑定Steam账号,从而获得更多权限,有疑问加群:762993431"); 171 | return Plugin_Handled; 172 | } 173 | } 174 | // if (GetConVarBool(g_hChannelEnable) && g_bQQTrigger[client]) { 175 | // if (strlen(sArgs) <= 0 || sArgs[0] == '!' || sArgs[0] == '.' || sArgs[0] == '/') { 176 | // return Plugin_Continue; 177 | // } 178 | // char name[LENGTH_NAME]; 179 | // GetClientName(client, name, sizeof(name)); 180 | // char words[LENGTH_MESSAGE]; 181 | // strcopy(words, sizeof(words), sArgs); 182 | // StripQuotes(words); 183 | // MessageToQQ(client, name, words); 184 | // } 185 | return Plugin_Continue; 186 | } 187 | -------------------------------------------------------------------------------- /scripting/csgowiki/kicker.sp: -------------------------------------------------------------------------------- 1 | // kick player have no csgowiki account 2 | 3 | public Action:AutoKickerCallback(Handle timer, client) { 4 | if (!IsPlayer(client)) 5 | return Plugin_Handled; 6 | if (g_aPlayerStateBind[client] == e_bBinded) 7 | return Plugin_Handled; 8 | char client_name[LENGTH_NAME]; 9 | GetClientName(client, client_name, sizeof(client_name)); 10 | KickClient(client, "请前往mycsgolab.com绑定steam账号(防止熊服),欢迎加入交流群:762993431"); 11 | PrintToChatAll("%s 玩家[\x0F%s\x01] 由于未绑定csgolab账户而踢出", PREFIX, client_name); 12 | return Plugin_Handled; 13 | } -------------------------------------------------------------------------------- /scripting/csgowiki/menus/menu_option.sp: -------------------------------------------------------------------------------- 1 | 2 | void GetAllProMatchStat(client) { 3 | new Handle:menuhandle = CreateMenu(ProMatchInfoMenuCallback); 4 | SetMenuTitle(menuhandle, "职业比赛合集"); 5 | 6 | for (new idx = g_aProMatchInfo.Length - 1; idx >= 0; idx--) { 7 | char team1[LENGTH_NAME], team2[LENGTH_NAME], time[LENGTH_NAME]; 8 | char matchId[LENGTH_NAME]; 9 | JSONObject arrval = view_as(g_aProMatchInfo.Get(idx)); 10 | JSONObject teamInfo_1 = view_as(arrval.Get("team1")); 11 | JSONObject teamInfo_2 = view_as(arrval.Get("team2")); 12 | teamInfo_1.GetString("name", team1, sizeof(team1)); 13 | teamInfo_2.GetString("name", team2, sizeof(team2)); 14 | int score1 = teamInfo_1.GetInt("result"); 15 | int score2 = teamInfo_2.GetInt("result"); 16 | arrval.GetString("time", time, sizeof(time)); 17 | arrval.GetString("matchId", matchId, sizeof(matchId)); 18 | char msg[LENGTH_NAME * 4]; 19 | Format(msg, sizeof(msg), "[%s] %d : %d [%s] (%s)", team1, score1, score2, team2, time); 20 | AddMenuItem(menuhandle, matchId, msg); 21 | } 22 | SetMenuPagination(menuhandle, 7); 23 | SetMenuExitBackButton(menuhandle, true); 24 | SetMenuExitButton(menuhandle, true); 25 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 26 | } 27 | 28 | 29 | public ProMatchInfoMenuCallback(Handle:menuhandle, MenuAction:action, client, Position) { 30 | if (MenuAction_Select == action) { 31 | decl String:matchId[LENGTH_NAME]; 32 | GetMenuItem(menuhandle, Position, matchId, sizeof(matchId)); 33 | 34 | // set index 35 | for (new idx = 0; idx < g_aProMatchInfo.Length; idx++) { 36 | char _matchId[LENGTH_NAME]; 37 | JSONObject arrval = view_as(g_aProMatchInfo.Get(idx)); 38 | arrval.GetString("matchId", _matchId, sizeof(_matchId)); 39 | if (StrEqual(matchId, _matchId)) { 40 | g_aProMatchIndex[client] = idx; 41 | break; 42 | } 43 | } 44 | ClientCommand(client, "sm_wikipro"); 45 | } 46 | else if (MenuAction_Cancel == action) { 47 | ClientCommand(client, "sm_option"); 48 | } 49 | } 50 | 51 | public Action:Command_Option(client, args) { 52 | Panel panel = new Panel(); 53 | 54 | panel.SetTitle("个人设置") 55 | 56 | if (g_bAutoThrow[client]) { 57 | panel.DrawItem("道具开启自动投掷:开"); 58 | } 59 | else { 60 | panel.DrawItem("道具开启自动投掷:关"); 61 | } 62 | panel.DrawItem("快捷道具上传(双击E):关", ITEMDRAW_DISABLED); 63 | 64 | panel.DrawItem("职业道具场次选择"); 65 | panel.DrawItem(" ", ITEMDRAW_SPACER); 66 | panel.DrawItem(" ", ITEMDRAW_SPACER); 67 | panel.DrawItem(" ", ITEMDRAW_SPACER); 68 | panel.DrawItem("返回", ITEMDRAW_CONTROL); 69 | panel.DrawItem("退出", ITEMDRAW_CONTROL); 70 | 71 | panel.Send(client, OptionPanelHandler, MENU_TIME_FOREVER); 72 | 73 | delete panel; 74 | return Plugin_Handled; 75 | } 76 | 77 | public OptionPanelHandler(Handle:menu, MenuAction:action, client, Position) { 78 | if (action == MenuAction_Select) { 79 | switch(Position) { 80 | case 1: g_bAutoThrow[client] = !g_bAutoThrow[client], PrintToChat(client, "%s \x04设置已更改", PREFIX), ClientCommand(client, "sm_option"); 81 | case 2: PrintToChat(client, "%s \x0E功能未开放,敬请期待...", PREFIX), ClientCommand(client, "sm_option"); 82 | case 3: GetAllProMatchStat(client); 83 | case 7: ClientCommand(client, "sm_m"); 84 | case 8: CloseHandle(menu); 85 | } 86 | } 87 | } 88 | 89 | void ResetDefaultOption(client) { 90 | g_bAutoThrow[client] = true; 91 | } 92 | -------------------------------------------------------------------------------- /scripting/csgowiki/menus/menu_wiki.sp: -------------------------------------------------------------------------------- 1 | // implement menus 2 | 3 | // 道具分类 第一层menu 4 | void Menu_UtilityWiki_v1(client) { 5 | if (!IsPlayer(client)) return; 6 | new Handle:menuhandle = CreateMenu(Menu_UtilityWiki_v1_CallBack); 7 | SetMenuTitle(menuhandle, "CSGOWiki道具分类"); 8 | 9 | AddMenuItem(menuhandle, "smoke", "烟雾弹"); 10 | AddMenuItem(menuhandle, "flash", "闪光弹"); 11 | AddMenuItem(menuhandle, "grenade", "手雷"); 12 | AddMenuItem(menuhandle, "molotov", "燃烧弹"); 13 | 14 | AddMenuItem(menuhandle, "startspot", ">>附近起点道具<<"); 15 | AddMenuItem(menuhandle, "endspot", ">>附近落点道具<<"); 16 | 17 | SetMenuExitBackButton(menuhandle, true); 18 | SetMenuExitButton(menuhandle, true); 19 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 20 | } 21 | 22 | 23 | public Menu_UtilityWiki_v1_CallBack(Handle:menuhandle, MenuAction:action, client, Position) { 24 | if (!IsPlayer(client)) return; 25 | if (action == MenuAction_Select) { 26 | decl String:Item[10]; 27 | GetMenuItem(menuhandle, Position, Item, sizeof(Item)); 28 | if (StrEqual(Item, "endspot")) { 29 | GetFilterCollection(client, "end"); 30 | } 31 | else if (StrEqual(Item, "startspot")) { 32 | GetFilterCollection(client, "start"); 33 | } 34 | else { 35 | Menu_UtilityWiki_v2(client, Item); 36 | } 37 | } 38 | else if (MenuAction_Cancel == action) { 39 | ClientCommand(client, "sm_m"); 40 | } 41 | } 42 | 43 | // 单个道具汇总菜单 44 | void Menu_UtilityWiki_v2(client, char[] utTinyName) { 45 | if (!IsPlayer(client)) return; 46 | new Handle:menuhandle = CreateMenu(Menu_UtilityWiki_v2_CallBack); 47 | char utNameZh[LENGTH_UTILITY_ZH]; 48 | char menuTitle[LENGTH_UTILITY_ZH]; 49 | Utility_TinyName2Zh(utTinyName, "%s", utNameZh); 50 | Format(menuTitle, LENGTH_UTILITY_ZH, "==== %s合集 ====", utNameZh); 51 | SetMenuTitle(menuhandle, menuTitle); 52 | 53 | int typeCount = 0; 54 | for (new idx = 0; idx < g_jaUtilityCollection.Length; idx++) { 55 | JSONObject arrval = view_as(g_jaUtilityCollection.Get(idx)); 56 | char utId[LENGTH_UTILITY_ID], utTitle[LENGTH_NAME], utType[LENGTH_UTILITY_TINY]; 57 | // int specFlag = 0; 58 | 59 | arrval.GetString("id", utId, LENGTH_UTILITY_ID); 60 | arrval.GetString("name", utTitle, LENGTH_NAME); 61 | arrval.GetString("type", utType, LENGTH_UTILITY_TINY); 62 | // specFlag = arrval.GetInt(3); 63 | if (StrEqual(utType, utTinyName)) { 64 | char msg[LENGTH_NAME + LENGTH_UTILITY_ZH + 8]; 65 | Format(msg, sizeof(msg), "[%s] %s", utNameZh, utTitle); 66 | // if (specFlag == 1) Format(msg, sizeof(msg), "%s *走投*", msg); 67 | // else if (specFlag == 2) Format(msg, sizeof(msg), "%s *跑投*", msg); 68 | AddMenuItem(menuhandle, utId, msg); 69 | typeCount ++; 70 | } 71 | // delete arrval; 72 | } 73 | if (typeCount == 0) { 74 | PrintToChat(client, "%s CSGOWiki目前未收录该种类道具", PREFIX); 75 | Menu_UtilityWiki_v1(client); 76 | return; 77 | } 78 | 79 | SetMenuPagination(menuhandle, 7); 80 | SetMenuExitBackButton(menuhandle, true); 81 | SetMenuExitButton(menuhandle, true); 82 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 83 | } 84 | 85 | 86 | public Menu_UtilityWiki_v2_CallBack(Handle:menuhandle, MenuAction:action, client, Position) { 87 | if (!IsPlayer(client)) return; 88 | if (MenuAction_Select == action) { 89 | decl String:utId[LENGTH_UTILITY_ID]; 90 | GetMenuItem(menuhandle, Position, utId, LENGTH_UTILITY_ID); 91 | 92 | if (e_cDefault != g_aPlayerStatus[client]) { 93 | PrintToChat(client, "%s \x02道具上传过程中,无法使用wiki功能", PREFIX); 94 | return; 95 | } 96 | GetUtilityDetail(client, utId); 97 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 98 | } 99 | else if (MenuAction_Cancel == action) { 100 | Menu_UtilityWiki_v1(client); 101 | } 102 | } 103 | 104 | public Action:ReqLockTimerCallback(Handle:timer, client) { 105 | g_aReqLock[client] = false; 106 | } 107 | 108 | // 用户搜索结果菜单 109 | void Menu_UtilityWiki_v3(client) { 110 | if (!IsPlayer(client)) return; 111 | if (g_aUtFilterCollection[client].Length == 0) { 112 | PrintToChat(client, "%s \x10你所在区域没有找到道具记录", PREFIX); 113 | Menu_UtilityWiki_v1(client); 114 | return; 115 | } 116 | 117 | new Handle:menuhandle = CreateMenu(Menu_UtilityWiki_v3_CallBack); 118 | SetMenuTitle(menuhandle, "=== 查询到的道具 ==="); 119 | 120 | for (new idx = 0; idx < g_aUtFilterCollection[client].Length; idx ++) { 121 | JSONObject arrval = view_as(g_aUtFilterCollection[client].Get(idx)); 122 | char utId[LENGTH_UTILITY_ID], utTitle[LENGTH_NAME], utType[LENGTH_UTILITY_TINY]; 123 | char utNameZh[LENGTH_UTILITY_ZH]; 124 | arrval.GetString("id", utId, LENGTH_UTILITY_ID); 125 | arrval.GetString("name", utTitle, LENGTH_NAME); 126 | arrval.GetString("type", utType, LENGTH_UTILITY_TINY); 127 | Utility_TinyName2Zh(utType, "%s", utNameZh); 128 | char msg[LENGTH_NAME + LENGTH_UTILITY_ZH + 8]; 129 | Format(msg, sizeof(msg), "[%s] %s", utNameZh, utTitle); 130 | AddMenuItem(menuhandle, utId, msg); 131 | delete arrval; 132 | } 133 | SetMenuPagination(menuhandle, 7); 134 | SetMenuExitBackButton(menuhandle, true); 135 | SetMenuExitButton(menuhandle, true); 136 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 137 | } 138 | 139 | public Menu_UtilityWiki_v3_CallBack(Handle:menuhandle, MenuAction:action, client, Position) { 140 | if (!IsPlayer(client)) return; 141 | if (MenuAction_Select == action) { 142 | decl String:utId[LENGTH_UTILITY_ID]; 143 | GetMenuItem(menuhandle, Position, utId, LENGTH_UTILITY_ID); 144 | GetUtilityDetail(client, utId); 145 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 146 | } 147 | else if (MenuAction_Cancel == action) { 148 | Menu_UtilityWiki_v1(client); 149 | } 150 | } -------------------------------------------------------------------------------- /scripting/csgowiki/menus/menu_wikiop.sp: -------------------------------------------------------------------------------- 1 | // csgowiki operator tools 2 | 3 | public Action:Command_Wikiop(client, args) { 4 | Panel panel = new Panel(); 5 | 6 | panel.SetTitle("CSGOWiki管理员工具") 7 | 8 | if (GetConVarBool(g_hCSGOWikiEnable)) 9 | panel.DrawItem("CSGOWiki总开关:开"); 10 | else 11 | panel.DrawItem("CSGOWiki总开关:关"); 12 | 13 | new Flag = ITEMDRAW_DEFAULT; 14 | if (!GetConVarBool(g_hCSGOWikiEnable)) 15 | Flag = ITEMDRAW_DISABLED; 16 | 17 | if (GetConVarBool(g_hOnUtilitySubmit)) 18 | panel.DrawItem("道具上传功能:开", Flag); 19 | else 20 | panel.DrawItem("道具上传功能:关", Flag); 21 | 22 | if (GetConVarBool(g_hOnUtilityWiki)) 23 | panel.DrawItem("道具学习功能:开", Flag); 24 | else 25 | panel.DrawItem("道具学习功能:关", Flag); 26 | 27 | panel.DrawText(" "); 28 | panel.DrawItem("第三方插件设置"); 29 | 30 | panel.DrawItem(" ", ITEMDRAW_SPACER); 31 | panel.DrawItem(" ", ITEMDRAW_SPACER); 32 | 33 | panel.DrawItem("返回", ITEMDRAW_CONTROL); 34 | panel.DrawItem("退出", ITEMDRAW_CONTROL); 35 | 36 | panel.Send(client, WikiopPanelHandler, MENU_TIME_FOREVER); 37 | 38 | delete panel; 39 | return Plugin_Handled; 40 | } 41 | 42 | 43 | public WikiopPanelHandler(Handle:menu, MenuAction:action, client, Position) { 44 | if (action == MenuAction_Select) { 45 | switch(Position) { 46 | case 1: SetConVarBool(g_hCSGOWikiEnable, !GetConVarBool(g_hCSGOWikiEnable), true, true), ClientCommand(client, "sm_wikiop"); 47 | case 2: SetConVarBool(g_hOnUtilitySubmit, !GetConVarBool(g_hOnUtilitySubmit), true, true), ClientCommand(client, "sm_wikiop"); 48 | case 3: SetConVarBool(g_hOnUtilityWiki, !GetConVarBool(g_hOnUtilityWiki), true, true), ClientCommand(client, "sm_wikiop"); 49 | case 4: PrintToChat(client, "%s \x0E功能未开放,敬请期待...", PREFIX), ClientCommand(client, "sm_wikiop"); 50 | case 7: ClientCommand(client, "sm_m"); 51 | case 8: CloseHandle(menu); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /scripting/csgowiki/menus/menu_wikipro.sp: -------------------------------------------------------------------------------- 1 | public Action:Command_WikiPro(client, args) { 2 | if (!check_function_on(g_hOnUtilityWiki, "\x02道具学习插件关闭,请联系服务器管理员", client)) { 3 | return; 4 | } 5 | 6 | if (BotMimicFix_IsPlayerMimicing(client)) { 7 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 8 | return; 9 | } 10 | if (g_aProMatchIndex[client] == -1) { // not set 11 | PrintToChat(client, "%s \x05请先选择职业比赛场次,已自动跳转选择菜单,如未跳转,请输入\x02!option\x05选择。", PREFIX); 12 | GetAllProMatchStat(client); 13 | return; 14 | } 15 | CreateProRoundMenu(client); 16 | } 17 | 18 | void CreateProRoundMenu(client) { 19 | JSONObject picked_info = view_as(g_aProMatchInfo.Get(g_aProMatchIndex[client])); 20 | char team1[LENGTH_NAME], team2[LENGTH_NAME]; 21 | JSONObject teamInfo_1 = view_as(picked_info.Get("team1")); 22 | JSONObject teamInfo_2 = view_as(picked_info.Get("team2")); 23 | teamInfo_1.GetString("name", team1, sizeof(team1)); 24 | teamInfo_2.GetString("name", team2, sizeof(team2)); 25 | int score1 = teamInfo_1.GetInt("result"); 26 | int score2 = teamInfo_2.GetInt("result"); 27 | char title[LENGTH_NAME * 4]; 28 | Format(title, sizeof(title), "[%s] %d : %d [%s] 回合选择", team1, score1, score2, team2); 29 | 30 | new Handle:menuhandle = CreateMenu(ProMatchRoundMenuCallback); 31 | SetMenuTitle(menuhandle, title); 32 | 33 | int maxround_int = picked_info.GetInt("maxround"); 34 | for (new round_count = 1; round_count <= maxround_int; round_count++) { 35 | char round_str[4]; 36 | IntToString(round_count, round_str, sizeof(round_str)); 37 | char item[LENGTH_MESSAGE]; 38 | Format(item, sizeof(item), "第%s回合", round_str); 39 | AddMenuItem(menuhandle, round_str, item); 40 | } 41 | 42 | SetMenuPagination(menuhandle, 7); 43 | SetMenuExitBackButton(menuhandle, true); 44 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 45 | } 46 | 47 | public ProMatchRoundMenuCallback(Handle:menuhandle, MenuAction:action, client, Position) { 48 | if (MenuAction_Select == action) { 49 | decl String:round_str[4]; 50 | GetMenuItem(menuhandle, Position, round_str, sizeof(round_str)); 51 | 52 | ShowProListInRound(client, round_str); 53 | } 54 | else if (MenuAction_Cancel == action) { 55 | ClientCommand(client, "sm_m"); 56 | } 57 | } 58 | 59 | void ShowProListInRound(client, char round_str[4]) { 60 | if (g_aProMatchIndex[client] == -1) { 61 | return; 62 | } 63 | if (BotMimicFix_IsPlayerMimicing(client)) { 64 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 65 | return; 66 | } 67 | char _matchId[LENGTH_NAME]; 68 | char url[LENGTH_MESSAGE]; 69 | JSONObject arrval = view_as(g_aProMatchInfo.Get(g_aProMatchIndex[client])); 70 | arrval.GetString("matchId", _matchId, sizeof(_matchId)); 71 | Format(url, sizeof(url), "https://api.hx-w.top/%s/%s/round%s", g_sCurrentMap, _matchId, round_str); 72 | HTTPRequest ProDetailRequest = new HTTPRequest(url); 73 | DataPack pack = new DataPack(); 74 | pack.WriteCell(client); 75 | pack.WriteString(round_str); 76 | ProDetailRequest.Get(ProRoundResponseCallback, pack); 77 | } 78 | 79 | void ProRoundResponseCallback(HTTPResponse response, DataPack pack) { 80 | pack.Reset(); 81 | int client = pack.ReadCell(); 82 | char round_str[4]; 83 | pack.ReadString(round_str, sizeof(round_str)); 84 | if (response.Status == HTTPStatus_OK) { 85 | delete g_aProMatchDetail[client]; 86 | g_aProMatchDetail[client] = new JSONArray(); 87 | JSONArray resp_json = view_as(response.Data); 88 | for (int idx = 0; idx < resp_json.Length; idx++) { 89 | JSONObject arrval = view_as(resp_json.Get(idx)); 90 | g_aProMatchDetail[client].Push(arrval); 91 | } 92 | // g_aProMatchDetail[client] = view_as(response.Data); 93 | CreateProDetailMenu(client, round_str); 94 | } 95 | else { 96 | PrintToChatAll("%s \x02连接至api.hx-w.top失败:%d", PREFIX, response.Status); 97 | } 98 | } 99 | 100 | void CreateProDetailMenu(client, char round_str[4]) { 101 | if (g_aProMatchDetail[client].Length == 0) { 102 | PrintToChat(client, "%s \x0F请求的数据出错,请重新选择比赛数据", PREFIX); 103 | GetAllProMatchStat(client); 104 | return; 105 | } 106 | 107 | char title[LENGTH_NAME]; 108 | Format(title, sizeof(title), "第%s回合道具记录", round_str); 109 | 110 | new Handle:menuhandle = CreateMenu(ProMatchDetailMenuCallback); 111 | SetMenuTitle(menuhandle, title); 112 | 113 | char playerName[LENGTH_NAME]; 114 | char utFullName[LENGTH_UTILITY_FULL]; 115 | char utZhName[LENGTH_UTILITY_ZH]; 116 | char item[LENGTH_NAME * 4]; 117 | char utId[LENGTH_UTILITY_ID]; 118 | for (new idx = 0; idx < g_aProMatchDetail[client].Length; idx++) { 119 | JSONArray curr = view_as(g_aProMatchDetail[client].Get(idx)); 120 | curr.GetString(11, playerName, sizeof(playerName)); 121 | curr.GetString(17, utFullName, sizeof(utFullName)); 122 | int round_throw_time = RoundFloat(curr.GetFloat(10)); 123 | int round_remain_secs = 55 + 60 - round_throw_time; 124 | int round_remain_min = round_remain_secs / 60; 125 | round_remain_secs %= 60; 126 | Utility_FullName2Zh(utFullName, "%s", utZhName); 127 | IntToString(idx, utId, sizeof(utId)); 128 | Format(item, sizeof(item), "[%s] %2d:%2d <%s>投掷", utZhName, round_remain_min, round_remain_secs, playerName); 129 | AddMenuItem(menuhandle, utId, item); 130 | } 131 | SetMenuPagination(menuhandle, 7); 132 | SetMenuExitBackButton(menuhandle, true); 133 | DisplayMenu(menuhandle, client, MENU_TIME_FOREVER); 134 | } 135 | 136 | public ProMatchDetailMenuCallback(Handle:menuhandle, MenuAction:action, client, Position) { 137 | if (MenuAction_Select == action) { 138 | decl String:utId[LENGTH_UTILITY_ID]; 139 | GetMenuItem(menuhandle, Position, utId, sizeof(utId)); 140 | int utId_int = StringToInt(utId); 141 | ShowProUtilityDetail(client, utId_int); 142 | DisplayMenuAtItem(menuhandle, client, GetMenuSelectionPosition(), MENU_TIME_FOREVER); 143 | } 144 | else if (MenuAction_Cancel == action) { 145 | CreateProRoundMenu(client); 146 | } 147 | } 148 | 149 | void ShowProUtilityDetail(client, int utId) { 150 | char utType[LENGTH_UTILITY_FULL], playerName[LENGTH_NAME], teamName[LENGTH_NAME]; 151 | char eventName[LENGTH_MESSAGE]; 152 | float throwPos[DATA_DIM], startAngle[DATA_DIM], velocity[DATA_DIM]; 153 | float entityPos[DATA_DIM]; 154 | 155 | JSONArray detail_json = view_as(g_aProMatchDetail[client].Get(utId)); 156 | JSONObject match_json = view_as(g_aProMatchInfo.Get(g_aProMatchIndex[client])); 157 | 158 | detail_json.GetString(17, utType, sizeof(utType)); 159 | detail_json.GetString(11, playerName, sizeof(playerName)); 160 | detail_json.GetString(13, teamName, sizeof(teamName)); 161 | match_json.GetString("event", eventName, sizeof(eventName)); 162 | throwPos[0] = detail_json.GetFloat(14); 163 | throwPos[1] = detail_json.GetFloat(15); 164 | throwPos[2] = detail_json.GetFloat(16); 165 | velocity[0] = detail_json.GetFloat(18); 166 | velocity[1] = detail_json.GetFloat(19); 167 | velocity[2] = detail_json.GetFloat(20); 168 | entityPos[0] = detail_json.GetFloat(21); 169 | entityPos[1] = detail_json.GetFloat(22); 170 | entityPos[2] = detail_json.GetFloat(23); 171 | startAngle[0] = detail_json.GetFloat(0); 172 | startAngle[1] = detail_json.GetFloat(1); 173 | startAngle[2] = 0.0; 174 | 175 | char utNameZh[LENGTH_UTILITY_ZH], utWeaponCmd[LENGTH_UTILITY_ZH]; 176 | Utility_FullName2Zh(utType, "%s", utNameZh); 177 | Utility_TinyName2Weapon(utType, utWeaponCmd, client); 178 | // tp player and get utility 179 | TeleportEntity(client, throwPos, startAngle, NULL_VECTOR); 180 | GivePlayerItem(client, utWeaponCmd); 181 | Format(utWeaponCmd, sizeof(utWeaponCmd), "use %s", utWeaponCmd); 182 | SetEntProp(client, Prop_Send, "m_iAmmo", 1); 183 | FakeClientCommand(client, utWeaponCmd); 184 | 185 | GrenadeType grenadeType = TinyName_2_GrenadeType(utType, client); 186 | CSU_ThrowGrenade(client, grenadeType, entityPos, velocity); 187 | } 188 | -------------------------------------------------------------------------------- /scripting/csgowiki/panel.sp: -------------------------------------------------------------------------------- 1 | // menu collect 2 | 3 | #include "csgowiki/menus/menu_option.sp" 4 | #include "csgowiki/menus/menu_wikipro.sp" 5 | #include "csgowiki/menus/menu_wiki.sp" 6 | #include "csgowiki/menus/menu_wikiop.sp" 7 | 8 | public Action:Command_Panel(client, args) { 9 | if (!IsPlayer(client)) return Plugin_Handled; 10 | Panel panel = new Panel(); 11 | 12 | panel.SetTitle("CSGOWiki操作面板") 13 | 14 | panel.DrawItem("社区道具合集[!wiki]"); 15 | panel.DrawItem("职业道具合集[!wikipro]"); 16 | panel.DrawItem("道具能力测试[!wikiquiz]", ITEMDRAW_DISABLED); 17 | panel.DrawText(" "); 18 | panel.DrawItem("道具上传[!submit]"); 19 | panel.DrawItem("道具反馈[!feedback]", ITEMDRAW_DISABLED); 20 | panel.DrawText(" "); 21 | panel.DrawItem("第三方插件面板[!wikidiy]", ITEMDRAW_DISABLED); 22 | panel.DrawItem("个人偏好设置[!option]"); 23 | panel.DrawItem("管理员工具[!wikiop]"); 24 | panel.DrawText(" "); 25 | panel.DrawItem("退出", ITEMDRAW_CONTROL); 26 | 27 | panel.Send(client, PanelHandler, MENU_TIME_FOREVER); 28 | 29 | delete panel; 30 | return Plugin_Handled; 31 | } 32 | 33 | public PanelHandler(Handle:menu, MenuAction:action, client, Position) { 34 | if (!IsPlayer(client)) return; 35 | if (action == MenuAction_Select) { 36 | switch(Position) { 37 | case 1: ClientCommand(client, "sm_wiki"); 38 | case 2: ClientCommand(client, "sm_wikipro"); 39 | case 3: ClientCommand(client, "sm_wikitest"); 40 | case 4: ClientCommand(client, "sm_submit"), ClientCommand(client, "sm_m"); 41 | case 5: ClientCommand(client, "sm_feedback"); 42 | case 6: ClientCommand(client, "sm_wikidiy"); 43 | case 7: ClientCommand(client, "sm_option"); 44 | case 8: ClientCommand(client, "sm_wikiop"); 45 | case 9: CloseHandle(menu); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /scripting/csgowiki/replay.sp: -------------------------------------------------------------------------------- 1 | // #include 2 | 3 | public Action Command_Record(client, args) { 4 | if (e_cDefault != g_aPlayerStatus[client]) { 5 | PrintToChat(client, "%s \x02已在道具上传状态,操作无效", PREFIX); 6 | return; 7 | } 8 | if (strlen(g_aLastUtilityId[client]) == 0) { 9 | PrintToChat(client, "%s \x02没有缓存的道具可以修改", PREFIX); 10 | return; 11 | } 12 | if (BotMimicFix_IsPlayerMimicing(client)) { 13 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 14 | return; 15 | } 16 | if (BotMimicFix_IsPlayerRecording(client)) { 17 | PrintToChat(client, "%s \x02正在录像", PREFIX); 18 | return; 19 | } 20 | PrintToChat(client, "%s \x04开始录像", PREFIX); 21 | BotMimicFix_StartRecording(client, g_aLastUtilityId[client], "csgowiki"); 22 | } 23 | 24 | public Action Command_StopRecord(client, args) { 25 | if (!IsPlayer(client)) { 26 | return; 27 | } 28 | if (!BotMimicFix_IsPlayerRecording(client)) { 29 | PrintToChat(client, "%s \x02还未开始录像", PREFIX); 30 | return; 31 | } 32 | PrintToChat(client, "%s \x02停止录像", PREFIX); 33 | if (strlen(g_aLastUtilityId[client]) != 0) { 34 | PrintToChat(client, "[DEBUG] %s", g_aLastUtilityId[client]); 35 | BotMimicFix_StopRecording(client, true, g_aLastUtilityId[client]); 36 | 37 | UploadPlayBack(client, g_aLastUtilityId[client]); 38 | } 39 | else { 40 | BotMimicFix_StopRecording(client, false); 41 | } 42 | } 43 | 44 | void UploadPlayBack(int client, char utid[LENGTH_UTILITY_ID]) { 45 | char filepath[PLATFORM_MAX_PATH]; 46 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/botmimic/csgowiki/%s/%s.rec", g_sCurrentMap, utid); 47 | if (!FileExists(filepath)) { 48 | PrintToChat(client, "%s \x02待上传文件不存在", PREFIX); 49 | return; 50 | } 51 | 52 | char apiHost[LENGTH_TOKEN]; 53 | char token[LENGTH_TOKEN]; 54 | char url[LENGTH_URL]; 55 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 56 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 57 | PrintToChat(client, "%s \x04开始上传录像:%s", PREFIX, utid); 58 | 59 | Format(url, sizeof(url), "%s/v2/utility/upload-playback-put/%s/?token=%s", apiHost, utid, token); 60 | HTTPRequest request = new HTTPRequest(url); 61 | DataPack pack = new DataPack(); 62 | pack.WriteCell(client); 63 | pack.WriteString(utid); 64 | request.UploadFile(filepath, BotMimicUploadCallback, pack); 65 | 66 | } 67 | 68 | void BotMimicUploadCallback(HTTPStatus status, DataPack pack) { 69 | pack.Reset(); 70 | int client = pack.ReadCell(); 71 | char utid[LENGTH_UTILITY_ID]; 72 | pack.ReadString(utid, sizeof(utid)); 73 | if (status != HTTPStatus_OK) { 74 | // Upload failed 75 | PrintToChat(client, "%s \x02录像文件上传失败:%d", PREFIX, status); 76 | DeleteReplayFileFromUtid(utid, false); 77 | return; 78 | } 79 | PrintToChat(client, "%s \x0A录像文件已上传CSGOLab", PREFIX); 80 | DeleteReplayFileFromUtid(utid, false); 81 | } 82 | 83 | // public void ExecuteCallback(bool success, const char[] command, System2ExecuteOutput output, any data) { 84 | // if (!success || output.ExitStatus != 0) { 85 | // PrintToChatAll("Couldn't execute commands successfully"); 86 | // } else { 87 | // char outputString[128]; 88 | // output.GetOutput(outputString, sizeof(outputString)); 89 | // PrintToChatAll("Output of the command: %s", outputString); 90 | // } 91 | // } 92 | 93 | bool StartRequestReplayFile(int client, char utility_id[LENGTH_UTILITY_ID], char utid[LENGTH_UTILITY_ID]) { 94 | if (!IsPlayer(client)) return false; 95 | char filepath[84]; 96 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/replays/%s.rec", utid); 97 | if (FileExists(filepath)) { // bug 98 | PrintToChat(client, "%s \x04命中缓存,开始播放录像", PREFIX); 99 | StartReplay(client, utid); 100 | return false; 101 | } 102 | if (IsPlayer(client)) 103 | PrintToChat(client, "%s \x09正在请求录像文件...", PREFIX); 104 | 105 | char apiHost[LENGTH_TOKEN]; 106 | char token[LENGTH_TOKEN]; 107 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 108 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 109 | char url[LENGTH_URL]; 110 | Format(url, sizeof(url), "%s/v2/utility/download-playback/?token=%s&article_id=%s", apiHost, token, utility_id); 111 | HTTPRequest request = new HTTPRequest(url); 112 | // request.AppendQueryParam("article_id", utility_id); 113 | DataPack pack = new DataPack(); 114 | pack.WriteCell(client); 115 | pack.WriteString(utid); 116 | request.DownloadFile(filepath, BotMimicDownloadCallback, pack); 117 | return true; 118 | } 119 | 120 | void BotMimicDownloadCallback(HTTPStatus status, DataPack pack) { 121 | pack.Reset(); 122 | int client = pack.ReadCell(); 123 | char utid[LENGTH_UTILITY_ID]; 124 | pack.ReadString(utid, sizeof(utid)); 125 | 126 | if (!IsPlayer(client)) { 127 | // client disconnected 128 | DeleteReplayFileFromUtid(utid); 129 | return; 130 | } 131 | if (status == HTTPStatus_NotFound || status == HTTPStatus_InternalServerError) { 132 | DeleteReplayFileFromUtid(utid); 133 | PrintToChat(client, "%s \x0A该道具的录像文件不存在,请联系管理员上传", PREFIX); 134 | return; 135 | } 136 | if (status != HTTPStatus_OK) { 137 | // Download failed 138 | DeleteReplayFileFromUtid(utid); 139 | PrintToChat(client, "%s \x02录像文件下载失败:%d", PREFIX, status); 140 | PrintToServer("%s \x04录像文件下载失败:%d", PREFIX, status); 141 | return; 142 | } 143 | PrintToChat(client, "%s \x04录像文件获取成功", PREFIX); 144 | if (BotMimicFix_IsPlayerMimicing(client)) { 145 | PrintToChat(client, "%s \x02请等待当前回放结束", client); 146 | } 147 | else { 148 | StartReplay(client, utid); 149 | } 150 | } 151 | 152 | public void StartReplay(int client, char utid[LENGTH_UTILITY_ID]) { 153 | if (!g_bBotMimicLoaded) { 154 | PrintToChat(client, "\x02BotMimic未加载,请联系管理员"); 155 | return; 156 | } 157 | DataPack fpack = new DataPack(); 158 | fpack.WriteCell(client); 159 | char filepath[84]; 160 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/replays/%s.rec", utid); 161 | fpack.WriteString(filepath); 162 | RequestFrame(BotMimicStartReplay, fpack); 163 | } 164 | 165 | void DeleteReplayFileFromUtid(char utid[LENGTH_UTILITY_ID], bool type=true) { 166 | char filepath[84]; 167 | if (type) { 168 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/replays/%s.rec", utid); 169 | } 170 | else { 171 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/botmimic/csgowiki/%s/%s.rec", g_sCurrentMap, utid); 172 | } 173 | if (FileExists(filepath)) { 174 | DeleteFile(filepath); 175 | } 176 | } 177 | 178 | public void BotMimicStartReplay(DataPack pack) { 179 | pack.Reset(); 180 | int client = pack.ReadCell(); 181 | char filepath[84]; 182 | pack.ReadString(filepath, sizeof(filepath)); 183 | 184 | BMError err = BotMimicFix_PlayRecordFromFile(client, filepath); 185 | if (err != BM_NoError) { 186 | char errString[128]; 187 | BotMimicFix_GetErrorString(err, errString, sizeof(errString)); 188 | LogError("Error playing record %s on client %d: %s", filepath, client, errString); 189 | } 190 | delete pack; 191 | } 192 | 193 | public void BotMimicFix_OnPlayerStopsMimicing(int client, char[] name, char[] category, char[] path) { 194 | if (IsPlayer(client)) { 195 | TeleportEntity(client, g_aStartPositions[client], g_aStartAngles[client], NULL_VECTOR); 196 | } 197 | } -------------------------------------------------------------------------------- /scripting/csgowiki/steam_bind.sp: -------------------------------------------------------------------------------- 1 | // implement steam_bind function 2 | 3 | // **** 不用再指令绑定了 ***** 4 | // public Action:Command_BindSteam(client, args) { 5 | // if (!GetConVarBool(g_hCSGOWikiEnable)) { 6 | // PrintToChat(client, "%s \x02CSGOWiki插件关闭,请联系服务器管理员", PREFIX); 7 | // return; 8 | // } 9 | // if (!args) { 10 | // PrintToChat(client, "%s \x02请前往mycsgolab绑定你的steam账号", PREFIX); 11 | // } 12 | // else { 13 | // char token[LENGTH_TOKEN]; 14 | // char steamid[LENGTH_STEAMID64]; 15 | // GetCmdArgString(token, LENGTH_TOKEN); 16 | // TrimString(token); 17 | // GetClientAuthId(client, AuthId_SteamID64, steamid, LENGTH_STEAMID64); 18 | // System2HTTPRequest httpRequest = new System2HTTPRequest( 19 | // SteamBindResponseCallback, 20 | // "https://api.mycsgolab.com/user/steambind/" 21 | // ) 22 | // httpRequest.SetData("steamid=%s&token=%s", steamid, token); 23 | // httpRequest.Any = client; 24 | // httpRequest.POST(); 25 | // delete httpRequest; 26 | // } 27 | // } 28 | 29 | // public SteamBindResponseCallback(bool success, const char[] error, System2HTTPRequest request, System2HTTPResponse response, HTTPRequestMethod method) { 30 | // int client = request.Any; 31 | // if (success) { 32 | // char[] content = new char[response.ContentLength + 1]; 33 | // char[] status = new char[LENGTH_STATUS]; 34 | // char[] aliasname = new char[LENGTH_NAME]; 35 | // int client_level = 0; 36 | // response.GetContent(content, response.ContentLength + 1); 37 | // JSON_Object json_obj = json_decode(content); 38 | // json_obj.GetString("status", status, LENGTH_STATUS); 39 | // if (StrEqual(status, "ok")) { 40 | // json_obj.GetString("aliasname", aliasname, LENGTH_NAME); 41 | // client_level = json_obj.GetInt("level"); 42 | // PrintToChat(client, "%s \x09账号绑定成功: \x04%s\x01(\x05Lv%d\x01)", PREFIX, aliasname, client_level); 43 | // g_aPlayerStateBind[client] = e_bBinded; 44 | // } 45 | // else { 46 | // char[] message = new char[LENGTH_NAME]; 47 | // json_obj.GetString("message", message, LENGTH_NAME); 48 | // PrintToChat(client, "%s \x02%s", PREFIX, message); 49 | // g_aPlayerStateBind[client] = e_bUnbind; 50 | // } 51 | // json_cleanup_and_delete(json_obj); 52 | // } 53 | // else { 54 | // PrintToChat(client, "%s \x02连接至mycsgolab失败", PREFIX); 55 | // } 56 | // } 57 | 58 | public Action:QuerySteamTimerCallback(Handle:timer, client) { 59 | if (GetConVarFloat(g_hWikiAutoKicker) == 0.0) { 60 | return; // 非公用服务器 61 | } 62 | char steamid[LENGTH_STEAMID64]; 63 | char token[LENGTH_TOKEN] = ""; 64 | GetClientAuthId(client, AuthId_SteamID64, steamid, LENGTH_STEAMID64); 65 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 66 | // GET 67 | char apiHost[LENGTH_TOKEN]; 68 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 69 | char url[LENGTH_MESSAGE]; 70 | Format(url, sizeof(url), "%s/user/steambind", apiHost); 71 | HTTPRequest httpRequest = new HTTPRequest(url); 72 | httpRequest.AppendQueryParam("steamid", steamid); 73 | httpRequest.AppendQueryParam("token", token); 74 | httpRequest.Get(QuerySteamResponseCallback, client); 75 | } 76 | 77 | void QuerySteamResponseCallback(HTTPResponse response, int client) { 78 | if (response.Status == HTTPStatus_OK) { 79 | char status[LENGTH_STATUS]; 80 | char aliasname[LENGTH_NAME]; 81 | JSONObject json_obj = view_as(response.Data); 82 | json_obj.GetString("status", status, LENGTH_STATUS); 83 | if (StrEqual(status, "ok")) { 84 | json_obj.GetString("aliasname", aliasname, LENGTH_NAME); 85 | int client_level = json_obj.GetInt("level"); 86 | PrintToChat(client, "%s \x09您已绑定网站账户: \x04%s\x01(\x05等级%d\x01)", PREFIX, aliasname, client_level); 87 | g_aPlayerStateBind[client] = e_bBinded; 88 | } 89 | else { 90 | char message[LENGTH_MESSAGE]; 91 | json_obj.GetString("message", message, sizeof(message)); 92 | if (StrEqual(message, "banned")) { 93 | char name[LENGTH_NAME]; 94 | GetClientName(client, name, sizeof(name)); 95 | PrintToChatAll("%s 玩家[\x02%s\x01] 被CSGOWiki封禁,已被踢出服务器", PREFIX, name); 96 | KickClient(client, "你已被CSGOWiki封禁,如有疑问请加群:762993431申诉"); 97 | } 98 | else { 99 | PrintToChat(client, "%s \x02您还没有在mycsgolab绑定steam账号~", PREFIX); 100 | g_aPlayerStateBind[client] = e_bUnbind; 101 | // set kicker 102 | float kicker_timer = GetConVarFloat(g_hWikiAutoKicker); 103 | if (kicker_timer > 0.0) { 104 | CreateTimer(kicker_timer * 60, AutoKickerCallback, client); 105 | PrintToChat(client, "%s \x0f由于你未绑定mycsgolab账号,根据设置,将在\x04%.2f\x0f分钟内将您踢出服务器", PREFIX, kicker_timer); 106 | PrintToChat(client, "%s 请前往\x04mycsgolab.com\x01绑定账号,以获得服务器内所有权限~", PREFIX); 107 | PrintToChat(client, "%s \x05绑定账号请前往\x09mycsgolab", PREFIX); 108 | } 109 | } 110 | } 111 | delete json_obj; 112 | // test 113 | ClientCommand(client, "sm_m"); 114 | } 115 | else { 116 | PrintToChat(client, "%s \x02连接至mycsgolab失败", PREFIX); 117 | } 118 | } 119 | 120 | void ResetSteamBindFlag(client) { 121 | g_aPlayerStateBind[client] = e_bUnknown; 122 | } 123 | -------------------------------------------------------------------------------- /scripting/csgowiki/utility_modify.sp: -------------------------------------------------------------------------------- 1 | // implement utility modify 2 | public Action:Command_Modify(client, args) { 3 | if (!check_function_on(g_hOnUtilitySubmit, "\x02道具上传功能关闭,请联系服务器管理员", client)) { 4 | return; 5 | } 6 | if (e_cDefault != g_aPlayerStatus[client]) { 7 | PrintToChat(client, "%s \x02已在道具上传状态,操作无效", PREFIX); 8 | return; 9 | } 10 | if (strlen(g_aLastArticleId[client]) == 0) { 11 | PrintToChat(client, "%s \x02没有缓存的道具可以修改", PREFIX); 12 | return; 13 | } 14 | GetCmdArgString(g_aPlayerToken[client], LENGTH_TOKEN); 15 | TrimString(g_aPlayerToken[client]); 16 | PrintToChat(client, "%s \x06道具修改功能开启", PREFIX); 17 | PrintToChat(client, "%s 你正在修改道具<\x04%s\x01>", PREFIX, g_aLastArticleId[client]); 18 | PrintToChat(client, "%s 输入\x04!abort\x01终止上传", PREFIX); 19 | GetClientAbsOrigin(client, g_aStartPositions[client]); 20 | GetClientEyeAngles(client, g_aStartAngles[client]); 21 | g_aPlayerStatus[client] = e_cM_ThrowReady; 22 | if (g_aPlayerUtilityPath[client] == null) { 23 | g_aPlayerUtilityPath[client] = new ArrayList(); 24 | } 25 | if (g_aPlayerUtilityPath[client] == null) { 26 | g_aPlayerUtilityPath[client] = new ArrayList(); 27 | } 28 | g_aPlayerUtilityPath[client].Clear(); 29 | } 30 | 31 | public Action:Command_Velocity(client, args) { 32 | PrintToChat(client, "%s \x02该接口已关闭", PREFIX); 33 | if (!check_function_on(g_hOnUtilitySubmit, "\x02道具上传功能关闭,请联系服务器管理员", client)) { 34 | return; 35 | } 36 | if (e_cDefault != g_aPlayerStatus[client]) { 37 | PrintToChat(client, "%s \x02已在道具上传状态,操作无效", PREFIX); 38 | return; 39 | } 40 | if (strlen(g_aLastArticleId[client]) == 0) { 41 | PrintToChat(client, "%s \x02没有缓存的道具可以修改", PREFIX); 42 | return; 43 | } 44 | PrintToChat(client, "%s \x06道具速度添加功能开启", PREFIX); 45 | PrintToChat(client, "%s 你正在修改道具<\x04%s\x01>", PREFIX, g_aLastArticleId[client]); 46 | PrintToChat(client, "%s 输入\x04!abort\x01终止上传", PREFIX); 47 | g_aPlayerStatus[client] = e_cV_ThrowReady; 48 | } 49 | 50 | void ClearPlayerToken(client) { 51 | strcopy(g_aPlayerToken[client], LENGTH_TOKEN, ""); 52 | } 53 | 54 | void TriggerWikiModify(client) { 55 | // param define 56 | char token[LENGTH_TOKEN] = ""; 57 | char utTinyName[LENGTH_UTILITY_TINY] = ""; 58 | bool wikiAction[CSGOWIKI_ACTION_NUM] = {}; // init all false 59 | char tickTag[LENGTH_STATUS] = ""; 60 | char steamid[LENGTH_STEAMID64] = ""; 61 | // param fix 62 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 63 | GrenadeType_2_Tinyname(g_aUtilityType[client], utTinyName); 64 | Action_Int2Array(client, wikiAction); 65 | TicktagGenerate(tickTag, wikiAction); 66 | GetClientAuthId(client, AuthId_SteamID64, steamid, LENGTH_STEAMID64); 67 | 68 | // PrintToChat(client, "total frame: %d; sampled frame: %d", g_iPlayerUtilityPathFrameCount[client], g_iPlayerUtilityPathFrameCount[client] / g_iUtilityPathInterval); 69 | // request 70 | char url[LENGTH_MESSAGE]; 71 | char apiHost[LENGTH_TOKEN]; 72 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 73 | Format(url, sizeof(url), "%s/v2/utility/modify/?token=%s", apiHost, token); 74 | HTTPRequest httpRequest = new HTTPRequest(url); 75 | httpRequest.SetHeader("Content-Type", "application/json"); 76 | 77 | JSONObject postData = new JSONObject(); 78 | postData.SetString("article_id", g_aLastArticleId[client]); 79 | postData.SetString("steam_id", steamid); 80 | postData.SetFloat("start_x", g_aStartPositions[client][0]); 81 | postData.SetFloat("start_y", g_aStartPositions[client][1]); 82 | postData.SetFloat("start_z", g_aStartPositions[client][2]); 83 | postData.SetFloat("end_x", g_aEndspotPositions[client][0]); 84 | postData.SetFloat("end_y", g_aEndspotPositions[client][1]); 85 | postData.SetFloat("end_z", g_aEndspotPositions[client][2]); 86 | postData.SetFloat("aim_pitch", g_aStartAngles[client][0]); 87 | postData.SetFloat("aim_yaw", g_aStartAngles[client][1]); 88 | postData.SetBool("is_run", view_as(wikiAction[e_wRun])); 89 | postData.SetBool("is_walk", view_as(wikiAction[e_wWalk])); 90 | postData.SetBool("is_jump", view_as(wikiAction[e_wJump])); 91 | postData.SetBool("is_duck", view_as(wikiAction[e_wDuck])); 92 | postData.SetBool("is_left", view_as(wikiAction[e_wLeftclick])); 93 | postData.SetBool("is_right", view_as(wikiAction[e_wRightclick])); 94 | postData.SetString("map_belong", g_sCurrentMap); 95 | postData.SetString("tickrate", tickTag); 96 | postData.SetString("utility_type", utTinyName); 97 | postData.SetFloat("throw_x", g_aThrowPositions[client][0]); 98 | postData.SetFloat("throw_y", g_aThrowPositions[client][1]); 99 | postData.SetFloat("throw_z", g_aThrowPositions[client][2]); 100 | postData.SetFloat("air_time", g_aUtilityAirtime[client]); 101 | postData.SetFloat("velocity_x", g_aUtilityVelocity[client][0]); 102 | postData.SetFloat("velocity_y", g_aUtilityVelocity[client][1]); 103 | postData.SetFloat("velocity_z", g_aUtilityVelocity[client][2]); 104 | 105 | httpRequest.Post(postData, WikiModifyResponseCallback, client); 106 | 107 | delete postData; 108 | } 109 | 110 | void WikiModifyResponseCallback(HTTPResponse response, int client) { 111 | if (response.Status == HTTPStatus_OK) { 112 | char status[LENGTH_STATUS]; 113 | JSONObject json_obj = view_as(response.Data); 114 | json_obj.GetString("status", status, LENGTH_STATUS); 115 | if (StrEqual(status, "ok")) { 116 | ShowModifyResult(client); 117 | } 118 | else { 119 | char message[LENGTH_NAME]; 120 | json_obj.GetString("detail", message, LENGTH_NAME); 121 | PrintToChat(client, "%s error: \x02%s", PREFIX, message); 122 | } 123 | delete json_obj; 124 | } 125 | else { 126 | PrintToChat(client, "%s error:\x02连接至mycsgolab失败 %d", PREFIX, response.Status); 127 | } 128 | ResetSingleClientSubmitState(client); 129 | } 130 | 131 | void ShowModifyResult(client) { 132 | char strAction[LENGTH_MESSAGE] = ""; 133 | Action_Int2Str(client, strAction); 134 | PrintToChat(client, "\x09 ------------------------------------- "); 135 | PrintToChat(client, "%s \x04已成功修改道具数据", PREFIX); 136 | PrintToChat(client, "%s [\x0F起点\x01] \x0D%f,%f,%f", PREFIX, g_aStartPositions[client][0], g_aStartPositions[client][1], g_aStartPositions[client][2]); 137 | PrintToChat(client, "%s [\x0F角度\x01] \x0D%f,%f, 0.0", PREFIX, g_aStartAngles[client][0], g_aStartAngles[client][1]); 138 | PrintToChat(client, "%s [\x0F出手点\x01] \x0D%f,%f,%f", PREFIX, g_aThrowPositions[client][0], g_aThrowPositions[client][1], g_aThrowPositions[client][2]); 139 | PrintToChat(client, "%s [\x0F落点\x01] \x0D%f,%f,%f", PREFIX, g_aEndspotPositions[client][0], g_aEndspotPositions[client][1], g_aEndspotPositions[client][2]); 140 | PrintToChat(client, "%s [\x0F动作列表\x01] \x0D%s", PREFIX, strAction); 141 | PrintToChat(client, "\x09 ------------------------------------- "); 142 | } 143 | -------------------------------------------------------------------------------- /scripting/csgowiki/utility_submit.sp: -------------------------------------------------------------------------------- 1 | // implement utility submit 2 | public Action:Command_Submit(client, args) { 3 | if (!check_function_on(g_hOnUtilitySubmit, "\x02道具上传功能关闭,请联系服务器管理员", client)) { 4 | return; 5 | } 6 | if (e_cDefault != g_aPlayerStatus[client]) { 7 | return; 8 | } 9 | if (BotMimicFix_IsPlayerMimicing(client)) { 10 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 11 | return; 12 | } 13 | PrintToChat(client, "%s \x06道具上传功能开启", PREFIX); 14 | PrintToChat(client, "%s 你接下来的道具投掷记录将会被自动上传至\x09mycsgolab", PREFIX); 15 | PrintToChat(client, "%s 输入\x04!abort\x01终止上传", PREFIX); 16 | GetClientAbsOrigin(client, g_aStartPositions[client]); 17 | GetClientEyeAngles(client, g_aStartAngles[client]); 18 | g_aPlayerStatus[client] = e_cThrowReady; 19 | 20 | if (g_aPlayerUtilityPath[client] == null) { 21 | g_aPlayerUtilityPath[client] = new ArrayList(); 22 | } 23 | g_aPlayerUtilityPath[client].Clear(); 24 | } 25 | 26 | public Action:Command_SubmitAbort(client, args) { 27 | if (e_cDefault != g_aPlayerStatus[client]) { 28 | g_aPlayerStatus[client] = e_cDefault; 29 | ResetSingleClientSubmitState(client); 30 | PrintToChat(client, "%s 已终止上传流程", PREFIX); 31 | } 32 | if (BotMimicFix_IsPlayerMimicing(client)) { 33 | BotMimicFix_StopPlayerMimic(client); 34 | } 35 | } 36 | 37 | // float float_reserve(float v) { 38 | // // float power = Pow(10.0, float(e)); 39 | // return float(RoundFloat(v * 10.0)) / 10.0; 40 | // } 41 | 42 | void OnPlayerRunCmdForUtilitySubmit(client, &buttons) { 43 | // record action => encoded 44 | if (e_cThrowReady == g_aPlayerStatus[client] || e_cM_ThrowReady == g_aPlayerStatus[client]) { 45 | for (new idx = 0; idx < CSGO_ACTION_NUM; idx++) { 46 | if ((g_aCsgoActionMap[idx] & buttons) && 47 | !(g_aActionRecord[client] & (1 << idx))) { 48 | g_aActionRecord[client] |= 1 << idx; 49 | } 50 | } 51 | } 52 | if (e_cAlreadyThrown == g_aPlayerStatus[client] || e_cM_AlreadyThrown == g_aPlayerStatus[client]) { 53 | if (g_iUtilityEntityId[client] != 0 && g_iPlayerUtilityPathFrameCount[client] % g_iUtilityPathInterval == 0) { 54 | float position[3]; 55 | GetEntPropVector(g_iUtilityEntityId[client], Prop_Send, "m_vecOrigin", position); 56 | g_aPlayerUtilityPath[client].Push(position[0]); 57 | g_aPlayerUtilityPath[client].Push(position[1]); 58 | g_aPlayerUtilityPath[client].Push(position[2]); 59 | } 60 | g_iPlayerUtilityPathFrameCount[client] ++; 61 | } 62 | } 63 | 64 | public void CSU_OnThrowGrenade(int client, int entity, GrenadeType grenadeType, 65 | const float origin[3], const float velocity[3]) { 66 | if (BotMimicFix_IsPlayerMimicing(client)) { 67 | AcceptEntityInput(entity, "Kill"); 68 | 69 | if (g_aUtilityVelocity[client][0] + g_aUtilityVelocity[client][1] + g_aUtilityVelocity[client][2] == 0.0) { 70 | PrintToChat(client, "%s \x06当前道具没有记录初始速度", PREFIX); 71 | } 72 | else { 73 | CSU_ThrowGrenade(client, grenadeType, g_aThrowPositions[client], g_aUtilityVelocity[client]); 74 | // PrintToChat(client, "%s \x05已自动投掷道具", PREFIX); 75 | } 76 | } 77 | if (g_aPlayerStatus[client] != e_cThrowReady && g_aPlayerStatus[client] != e_cM_ThrowReady && g_aPlayerStatus[client] != e_cV_ThrowReady) 78 | return; 79 | if (grenadeType == GrenadeType_None || grenadeType == GrenadeType_Decoy) 80 | return; 81 | g_iUtilityEntityId[client] = entity; 82 | g_aThrowPositions[client] = origin; 83 | g_aUtilityVelocity[client] = velocity; 84 | g_aUtilityAirtime[client] = GetEngineTime(); 85 | g_aUtilityType[client] = grenadeType; 86 | if (e_cM_ThrowReady == g_aPlayerStatus[client]) 87 | g_aPlayerStatus[client] = e_cM_AlreadyThrown; 88 | else if (e_cThrowReady == g_aPlayerStatus[client]) 89 | g_aPlayerStatus[client] = e_cAlreadyThrown; 90 | else { 91 | g_aPlayerStatus[client] = e_cDefault; 92 | // disable trigger velocity post 93 | } 94 | PrintToChat(client, "%s \x03已经记录你的动作,等待道具生效...", PREFIX); 95 | } 96 | 97 | void Event_HegrenadeDetonateForUtilitySubmit(Handle:event) { 98 | UtilityDetonateStat(event, GrenadeType_HE); 99 | } 100 | 101 | void Event_FlashbangDetonateForUtilitySubmit(Handle:event) { 102 | UtilityDetonateStat(event, GrenadeType_Flash); 103 | } 104 | 105 | void Event_SmokegrenadeDetonateForUtilitySubmit(Handle:event) { 106 | UtilityDetonateStat(event, GrenadeType_Smoke); 107 | } 108 | 109 | void Event_MolotovDetonateForUtilitySubmit(Handle:event) { 110 | UtilityDetonateStat(event, GrenadeType_Molotov); 111 | } 112 | 113 | // implement utility submit function 114 | void ResetSingleClientSubmitState(client) { 115 | g_aPlayerStatus[client] = e_cDefault; 116 | g_aActionRecord[client] = 0; 117 | g_iPlayerUtilityPathFrameCount[client] = 0; 118 | g_iUtilityEntityId[client] = 0; 119 | if (g_aPlayerUtilityPath[client] == null) { 120 | g_aPlayerUtilityPath[client] = new ArrayList(); 121 | } 122 | g_aPlayerUtilityPath[client].Clear(); 123 | } 124 | 125 | void ResetUtilitySubmitState() { 126 | for (new client = 0; client <= MAXPLAYERS; client++) { 127 | ResetSingleClientSubmitState(client); 128 | } 129 | } 130 | 131 | void UtilityDetonateStat(Handle:event, GrenadeType utCode) { 132 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 133 | if ((e_cAlreadyThrown == g_aPlayerStatus[client] 134 | || e_cM_AlreadyThrown == g_aPlayerStatus[client]) 135 | && utCode == g_aUtilityType[client]) { 136 | // next state 137 | g_aUtilityAirtime[client] = GetEngineTime() - g_aUtilityAirtime[client]; 138 | g_aEndspotPositions[client][0] = GetEventFloat(event, "x"); 139 | g_aEndspotPositions[client][1] = GetEventFloat(event, "y"); 140 | g_aEndspotPositions[client][2] = GetEventFloat(event, "z"); 141 | 142 | if (e_cM_AlreadyThrown == g_aPlayerStatus[client]) { 143 | g_aPlayerStatus[client] = e_cM_ThrowEnd; 144 | TriggerWikiModify(client); 145 | } 146 | else { 147 | g_aPlayerStatus[client] = e_cThrowEnd; 148 | TriggerWikiPost(client); 149 | } 150 | g_iPlayerUtilityPathFrameCount[client] = 0; 151 | g_iUtilityEntityId[client] = 0; 152 | if (g_aPlayerUtilityPath[client] == null) { 153 | g_aPlayerUtilityPath[client] = new ArrayList(); 154 | } 155 | g_aPlayerUtilityPath[client].Clear(); 156 | } 157 | } 158 | 159 | void TriggerWikiPost(client) { 160 | // post api 161 | 162 | // param define 163 | char token[LENGTH_TOKEN] = ""; 164 | char steamid[LENGTH_STEAMID64] = ""; 165 | char utTinyName[LENGTH_UTILITY_TINY] = ""; 166 | bool wikiAction[CSGOWIKI_ACTION_NUM] = {}; // init all false 167 | char tickTag[LENGTH_STATUS] = ""; 168 | // param fix 169 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 170 | GetClientAuthId(client, AuthId_SteamID64, steamid, LENGTH_STEAMID64); 171 | GrenadeType_2_Tinyname(g_aUtilityType[client], utTinyName); 172 | Action_Int2Array(client, wikiAction); 173 | TicktagGenerate(tickTag, wikiAction); 174 | 175 | // request 176 | char url[LENGTH_MESSAGE]; 177 | char apiHost[LENGTH_TOKEN]; 178 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 179 | Format(url, sizeof(url), "%s/v2/utility/submit/?token=%s", apiHost, token); 180 | HTTPRequest httpRequest = new HTTPRequest(url); 181 | httpRequest.SetHeader("Content-Type", "application/json"); 182 | JSONObject postData = new JSONObject(); 183 | // post data 184 | postData.SetString("steam_id", steamid); 185 | postData.SetFloat("start_x", g_aStartPositions[client][0]); 186 | postData.SetFloat("start_y", g_aStartPositions[client][1]); 187 | postData.SetFloat("start_z", g_aStartPositions[client][2]); 188 | postData.SetFloat("end_x", g_aEndspotPositions[client][0]); 189 | postData.SetFloat("end_y", g_aEndspotPositions[client][1]); 190 | postData.SetFloat("end_z", g_aEndspotPositions[client][2]); 191 | postData.SetFloat("aim_pitch", g_aStartAngles[client][0]); 192 | postData.SetFloat("aim_yaw", g_aStartAngles[client][1]); 193 | postData.SetBool("is_run", view_as(wikiAction[e_wRun])); 194 | postData.SetBool("is_walk", view_as(wikiAction[e_wWalk])); 195 | postData.SetBool("is_jump", view_as(wikiAction[e_wJump])); 196 | postData.SetBool("is_duck", view_as(wikiAction[e_wDuck])); 197 | postData.SetBool("is_left", view_as(wikiAction[e_wLeftclick])); 198 | postData.SetBool("is_right", view_as(wikiAction[e_wRightclick])); 199 | postData.SetString("map_belong", g_sCurrentMap); 200 | postData.SetString("tickrate", tickTag); 201 | postData.SetString("utility_type", utTinyName); 202 | postData.SetFloat("throw_x", g_aThrowPositions[client][0]); 203 | postData.SetFloat("throw_y", g_aThrowPositions[client][1]); 204 | postData.SetFloat("throw_z", g_aThrowPositions[client][2]); 205 | postData.SetFloat("air_time", g_aUtilityAirtime[client]); 206 | postData.SetFloat("velocity_x", g_aUtilityVelocity[client][0]); 207 | postData.SetFloat("velocity_y", g_aUtilityVelocity[client][1]); 208 | postData.SetFloat("velocity_z", g_aUtilityVelocity[client][2]); 209 | // postData.SetString("path", path); 210 | 211 | httpRequest.Post(postData, WikiPostResponseCallback, client); 212 | delete postData; 213 | } 214 | 215 | 216 | void WikiPostResponseCallback(HTTPResponse response, int client) { 217 | if (response.Status == HTTPStatus_OK) { 218 | char status[LENGTH_STATUS]; 219 | JSONObject json_obj = view_as(response.Data); 220 | 221 | json_obj.GetString("status", status, LENGTH_STATUS); 222 | if (StrEqual(status, "ok")) { 223 | char utId[LENGTH_UTILITY_ID]; 224 | json_obj.GetString("code", utId, LENGTH_UTILITY_ID); 225 | // upload path 226 | SaveUtilityPath(client, utId); 227 | UploadUtilityPath(client, utId); 228 | 229 | ShowResult(client, utId); 230 | } 231 | else { 232 | char message[LENGTH_NAME]; 233 | json_obj.GetString("message", message, LENGTH_NAME); 234 | PrintToChat(client, "%s \x02%s", PREFIX, message); 235 | } 236 | delete json_obj; 237 | } 238 | else { 239 | PrintToChat(client, "%s \x02连接至mycsgolab失败 %d", PREFIX, response.Status); 240 | } 241 | ResetSingleClientSubmitState(client); 242 | } 243 | 244 | void ShowResult(client, char[] utId) { 245 | char strAction[LENGTH_MESSAGE] = ""; 246 | Action_Int2Str(client, strAction); 247 | PrintToChat(client, "\x09 ------------------------------------- "); 248 | PrintToChat(client, "%s 已将道具记录上传至\x09mycsgolab\x01", PREFIX); 249 | PrintToChat(client, "%s [\x0F起点\x01] \x0D%f,%f,%f", PREFIX, g_aStartPositions[client][0], g_aStartPositions[client][1], g_aStartPositions[client][2]); 250 | PrintToChat(client, "%s [\x0F角度\x01] \x0D%f,%f, 0.0", PREFIX, g_aStartAngles[client][0], g_aStartAngles[client][1]); 251 | PrintToChat(client, "%s [\x0F出手点\x01] \x0D%f,%f,%f", PREFIX, g_aThrowPositions[client][0], g_aThrowPositions[client][1], g_aThrowPositions[client][2]); 252 | PrintToChat(client, "%s [\x0F落点\x01] \x0D%f,%f,%f", PREFIX, g_aEndspotPositions[client][0], g_aEndspotPositions[client][1], g_aEndspotPositions[client][2]); 253 | PrintToChat(client, "%s [\x0F动作列表\x01] \x0D%s", PREFIX, strAction); 254 | PrintToChat(client, "%s 该道具记录的唯一标识为<\x04%s\x01>", PREFIX, utId); 255 | PrintToChat(client, "%s 请在\x02尽快\x01登陆网站补全道具信息(图片和文字描述)", PREFIX); 256 | PrintToChat(client, "\x09 ------------------------------------- "); 257 | } 258 | 259 | void SaveUtilityPath(int client, char filename[LENGTH_UTILITY_ID]) { 260 | // 检查count 261 | if (g_aPlayerUtilityPath[client].Length / 3 != g_iPlayerUtilityPathFrameCount[client] / g_iUtilityPathInterval) { 262 | PrintToChat(client, "%s \x02道具路径数据记录错误:理论采样数 %d / 实际采样数 %d", PREFIX, g_iPlayerUtilityPathFrameCount[client] / g_iUtilityPathInterval, g_aPlayerUtilityPath[client].Length / 3); 263 | return; 264 | } 265 | 266 | char filepath[PLATFORM_MAX_PATH]; 267 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/path/%s.path", filename); 268 | File hFile = OpenFile(filepath, "wb"); 269 | if(hFile == null) { 270 | LogError("Can't open the record file for writing! (%s)", filepath); 271 | return; 272 | } 273 | hFile.WriteInt32(g_aPlayerUtilityPath[client].Length / 3); 274 | 275 | float pos[3]; 276 | for (int idx = 0; idx < g_aPlayerUtilityPath[client].Length; idx++) { 277 | pos[idx % 3] = view_as(g_aPlayerUtilityPath[client].Get(idx)); 278 | if (idx % 3 == 2) { 279 | hFile.Write(pos, 3, 4); 280 | } 281 | } 282 | 283 | delete hFile; 284 | } 285 | 286 | void UploadUtilityPath(int client, char utid[LENGTH_UTILITY_ID]) { 287 | char filepath[PLATFORM_MAX_PATH]; 288 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/path/%s.path", utid); 289 | if (!FileExists(filepath)) { 290 | PrintToChat(client, "%s \x02待上传文件不存在", PREFIX); 291 | return; 292 | } 293 | 294 | char apiHost[LENGTH_TOKEN]; 295 | char token[LENGTH_TOKEN]; 296 | char url[LENGTH_URL]; 297 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 298 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 299 | PrintToChat(client, "%s \x04开始上传路径文件:%s", PREFIX, utid); 300 | Format(url, sizeof(url), "%s/v2/utility/upload-path-put/%s/?token=%s", apiHost, utid, token); 301 | HTTPRequest request = new HTTPRequest(url); 302 | 303 | DataPack pack = new DataPack(); 304 | pack.WriteCell(client); 305 | pack.WriteString(utid); 306 | 307 | request.UploadFile(filepath, UploadUtilityPathCallback, pack); 308 | } 309 | 310 | void UploadUtilityPathCallback(HTTPStatus status, DataPack pack) { 311 | pack.Reset(); 312 | int client = pack.ReadCell(); 313 | char utid[LENGTH_UTILITY_ID]; 314 | pack.ReadString(utid, sizeof(utid)); 315 | 316 | // filepath 317 | char filepath[PLATFORM_MAX_PATH]; 318 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/csgowiki/path/%s.path", utid); 319 | 320 | if (status != HTTPStatus_OK) { 321 | PrintToChat(client, "%s \x02路径文件上传失败:%d", PREFIX, status); 322 | } 323 | else { 324 | PrintToChat(client, "%s \x0A路径文件已上传CSGOLab", PREFIX); 325 | } 326 | if (FileExists(filepath)) { 327 | DeleteFile(filepath); 328 | } 329 | } -------------------------------------------------------------------------------- /scripting/csgowiki/utility_wiki.sp: -------------------------------------------------------------------------------- 1 | // implement wiki 2 | 3 | public Action:Command_Wiki(client, args) { 4 | PluginVersionHint(client); 5 | 6 | if (!check_function_on(g_hOnUtilityWiki, "\x02道具学习插件关闭,请联系服务器管理员", client)) { 7 | return; 8 | } 9 | if (BotMimicFix_IsPlayerMimicing(client)) { 10 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 11 | return; 12 | } 13 | if (args >= 1) { 14 | char utId[LENGTH_TOKEN]; 15 | GetCmdArgString(utId, LENGTH_TOKEN); 16 | TrimString(utId); 17 | PrintToChat(client, "%s 正在请求道具<\x0E%s\x01>", PREFIX, utId); 18 | GetUtilityDetail(client, utId); 19 | } 20 | if (g_jaUtilityCollection == INVALID_HANDLE || g_jaUtilityCollection.Length < 10) { 21 | PrintToChat(client, "%s 道具合集初始化失败,正在重新请求数据...", PREFIX); 22 | GetAllCollection(client); 23 | } 24 | else { 25 | Menu_UtilityWiki_v1(client); 26 | } 27 | } 28 | 29 | public Action:Command_Refresh(client, args) { 30 | GetAllCollection(client); 31 | } 32 | 33 | void GetAllCollection(client=-1) { 34 | if (!check_function_on(g_hOnUtilityWiki, "")) return; 35 | char token[LENGTH_TOKEN]; 36 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 37 | 38 | char apiHost[LENGTH_TOKEN]; 39 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 40 | 41 | char url[LENGTH_MESSAGE]; 42 | Format(url, sizeof(url), "%s/v2/utility/filter", apiHost); 43 | HTTPRequest AllCollectionRequest = new HTTPRequest(url); 44 | AllCollectionRequest.AppendQueryParam("token", token); 45 | AllCollectionRequest.AppendQueryParam("mapname", g_sCurrentMap); 46 | AllCollectionRequest.AppendQueryParam("tickrate", "%d", g_iServerTickrate); 47 | 48 | AllCollectionRequest.Get(AllCollectionResponseCallback, client); 49 | 50 | // pro 51 | // if (g_aProMatchInfo == INVALID_HANDLE || g_aProMatchInfo.Length < 1) { 52 | Format(url, sizeof(url), "https://api.hx-w.top/%s", g_sCurrentMap); 53 | HTTPRequest ProCollectionRequest = new HTTPRequest(url); 54 | ProCollectionRequest.SetHeader("Content-Type", "application/json"); 55 | ProCollectionRequest.Get(ProCollectionResponseCallback, client); 56 | // } 57 | } 58 | 59 | void GetFilterCollection(client, char[] method) { 60 | float playerPos[DATA_DIM]; 61 | char token[LENGTH_TOKEN]; 62 | GetClientAbsOrigin(client, playerPos); 63 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 64 | 65 | char apiHost[LENGTH_TOKEN]; 66 | char url[LENGTH_MESSAGE]; 67 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 68 | Format(url, sizeof(url), "%s/v2/utility/filter", apiHost); 69 | 70 | HTTPRequest httpRequest = new HTTPRequest(url); 71 | httpRequest.AppendQueryParam("token", token); 72 | httpRequest.AppendQueryParam("mapname", g_sCurrentMap); 73 | httpRequest.AppendQueryParam("tickrate", "%d", g_iServerTickrate); 74 | // httpRequest.AppendQueryParam("method", method); 75 | if (StrEqual(method, "start")) { 76 | httpRequest.AppendQueryParam("start_x", "%f", playerPos[0]); 77 | httpRequest.AppendQueryParam("start_y", "%f", playerPos[1]); 78 | } 79 | else if (StrEqual(method, "end")) { 80 | httpRequest.AppendQueryParam("end_x", "%f", playerPos[0]); 81 | httpRequest.AppendQueryParam("end_y", "%f", playerPos[1]); 82 | } 83 | httpRequest.Get(FilterCollectionResponseCallback, client); 84 | } 85 | 86 | void GetUtilityDetail(client, char[] utId) { 87 | // lock 88 | float fWikiLimit = GetConVarFloat(g_hWikiReqLimit); 89 | if (BotMimicFix_IsPlayerMimicing(client)) { 90 | PrintToChat(client, "%s \x02正在播放录像", PREFIX); 91 | return; 92 | } 93 | if (g_aReqLock[client]) { 94 | PrintToChat(client, "%s \x07请求过快!\x01冷却时间:\x09%.2f\x01秒", PREFIX, fWikiLimit); 95 | return; 96 | } 97 | else { 98 | if (fWikiLimit != 0.0) { 99 | g_aReqLock[client] = true; 100 | CreateTimer(fWikiLimit, ReqLockTimerCallback, client); 101 | } 102 | } 103 | 104 | char token[LENGTH_TOKEN]; 105 | GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 106 | char apiHost[LENGTH_TOKEN]; 107 | GetConVarString(g_hApiHost, apiHost, sizeof(apiHost)); 108 | char steamid_[LENGTH_STEAMID64]; 109 | GetClientAuthId(client, AuthId_SteamID64, steamid_, LENGTH_STEAMID64); 110 | char player_name[LENGTH_NAME]; 111 | GetClientName(client, player_name, sizeof(player_name)); 112 | char url[LENGTH_MESSAGE]; 113 | Format(url, sizeof(url), "%s/v2/utility/detail", apiHost); 114 | 115 | HTTPRequest httpRequest = new HTTPRequest(url); 116 | httpRequest.AppendQueryParam("token", token); 117 | httpRequest.AppendQueryParam("article_id", utId); 118 | httpRequest.Get(UtilityDetailResponseCallback, client); 119 | 120 | // ===================================================== 121 | HTTPRequest postRequest = new HTTPRequest("http://ci.csgowiki.top:2333/trigger/wiki-player"); 122 | postRequest.SetHeader("Content-Type", "application/json"); 123 | 124 | JSONObject postData = new JSONObject(); 125 | postData.SetString("map_name", g_sCurrentMap); 126 | postData.SetString("steamid", steamid_); 127 | postData.SetString("player_name", player_name); 128 | 129 | postRequest.Post(postData, WikiPlayerTriggerResponseCallback); 130 | delete postData; 131 | } 132 | 133 | void ResetSingleClientWikiState(client, bool force_del=false) { 134 | if (strlen(g_aLastArticleId[client]) == 0) return; 135 | if (strlen(g_aLastUtilityId[client]) == 0) return; 136 | if (force_del) { 137 | DeleteReplayFileFromUtid(g_aLastUtilityId[client]); 138 | } 139 | else { 140 | bool candelete = true; 141 | for (int i = 0; i <= MaxClients; i++) { 142 | if (IsPlayer(i) && i != client && StrEqual(g_aLastUtilityId[client], g_aLastUtilityId[i])) { 143 | candelete = false; 144 | break; 145 | } 146 | } 147 | if (candelete) { 148 | DeleteReplayFileFromUtid(g_aLastUtilityId[client]); 149 | } 150 | } 151 | strcopy(g_aLastUtilityId[client], LENGTH_UTILITY_ID, ""); 152 | strcopy(g_aLastArticleId[client], LENGTH_UTILITY_ID, ""); 153 | } 154 | 155 | void ResetUtilityWikiState() { 156 | for (new client = 0; client <= MAXPLAYERS; client++) { 157 | ResetSingleClientWikiState(client, true); 158 | } 159 | } 160 | 161 | void AllCollectionResponseCallback(HTTPResponse response, int client) { 162 | if (response.Status == HTTPStatus_OK) { 163 | char status[LENGTH_STATUS]; 164 | JSONObject resp_json = view_as(response.Data); 165 | resp_json.GetString("status", status, LENGTH_STATUS); 166 | if (!StrEqual(status, "ok")) { 167 | if (client == -1) PrintToChatAll("%s \x02服务器数据请求失败,可能是token无效", PREFIX); 168 | else PrintToChat(client, "%s \x02服务器数据请求失败,可能是token无效", PREFIX); 169 | return; 170 | } 171 | 172 | g_jaUtilityCollection = view_as(resp_json.Get("utility_collection")); 173 | // show menu for Command_Wiki 174 | if (IsPlayer(client)) { 175 | Menu_UtilityWiki_v1(client); 176 | } 177 | // need delete? 178 | } 179 | else { 180 | if (client == -1) PrintToChatAll("%s \x02连接至mycsgolab失败:%d", PREFIX, response.Status); 181 | else PrintToChat(client, "%s \x02连接至mycsgolab失败:%d", PREFIX, response.Status); 182 | } 183 | } 184 | 185 | 186 | void ProCollectionResponseCallback(HTTPResponse response, int client) { 187 | if (IsPlayer(client)) { 188 | PrintToChat(client, "%s 职业比赛道具获取:%d", PREFIX, response.Status); 189 | } 190 | if (response.Status == HTTPStatus_OK) { 191 | JSONArray resp_json = view_as(response.Data); 192 | g_aProMatchInfo = new JSONArray(); 193 | for (int idx = 0; idx < resp_json.Length; idx++) { 194 | JSONObject arrval = view_as(resp_json.Get(idx)); 195 | g_aProMatchInfo.Push(arrval); 196 | } 197 | // g_aProMatchInfo = view_as(response.Data); 198 | } 199 | else { 200 | PrintToChatAll("%s \x02连接至api.hx-w.top失败:%d", PREFIX, response.Status); 201 | PrintToServer("%s \x02连接至api.hx-w.top失败:%d", PREFIX, response.Status); 202 | } 203 | } 204 | 205 | void FilterCollectionResponseCallback(HTTPResponse response, int client) { 206 | if (response.Status == HTTPStatus_OK) { 207 | char status[LENGTH_STATUS]; 208 | JSONObject resp_json = view_as(response.Data); 209 | resp_json.GetString("status", status, LENGTH_STATUS); 210 | if (StrEqual(status, "error")) { 211 | PrintToChat(client, "%s \x02服务器数据请求失败,可能是token无效", PREFIX); 212 | Menu_UtilityWiki_v1(client); 213 | } 214 | else if (StrEqual(status, "warning")) { 215 | PrintToChat(client, "%s \x02服务器数据请求失败,等级限制2级及以上", PREFIX); 216 | Menu_UtilityWiki_v1(client); 217 | } 218 | else if (StrEqual(status, "ok")) { 219 | g_aUtFilterCollection[client] = view_as(resp_json.Get("utility_collection")); 220 | // show menu for Command_Wiki 221 | Menu_UtilityWiki_v3(client); 222 | } 223 | delete resp_json; 224 | } 225 | else { 226 | PrintToChat(client, "%s \x02连接至mycsgolab失败:%d", PREFIX, response.Status); 227 | } 228 | } 229 | 230 | void UtilityDetailResponseCallback(HTTPResponse response, int client) { 231 | if (response.Status == HTTPStatus_OK) { 232 | char status[LENGTH_STATUS]; 233 | JSONObject resp_json = view_as(response.Data); 234 | resp_json.GetString("status", status, LENGTH_STATUS); 235 | char detail[1024]; 236 | resp_json.ToString(detail, sizeof(detail)); 237 | if (StrEqual(status, "error")) { 238 | PrintToChat(client, "%s \x02服务器数据请求失败,可能是token无效", PREFIX); 239 | } 240 | else if (StrEqual(status, "warning")) { 241 | PrintToChat(client, "%s \x02服务器数据请求失败,已超过当日请求次数限制", PREFIX); 242 | } 243 | else if (StrEqual(status, "ok")) { 244 | JSONObject json_obj = view_as(resp_json.Get("utility_detail")); 245 | ShowUtilityDetail(client, json_obj); 246 | } 247 | delete resp_json; 248 | } 249 | else { 250 | PrintToChat(client, "%s \x02连接至mycsgolab失败:%d", PREFIX, response.Status); 251 | } 252 | } 253 | 254 | 255 | void WikiPlayerTriggerResponseCallback(HTTPResponse response, any data) { 256 | if (response.Status != HTTPStatus_OK) { 257 | PrintToServer("wiki-player trigger error: %d", response.Status); 258 | } 259 | } 260 | 261 | void ShowUtilityDetail(client, JSONObject detail_json) { 262 | if (!IsPlayer(client)) return; 263 | // var define 264 | char utId[LENGTH_UTILITY_ID], utType[LENGTH_UTILITY_TINY], utTitle[LENGTH_NAME]; 265 | char utBrief[LENGTH_UTILITY_BRIEF], author[LENGTH_NAME]; 266 | char actionBody[LENGTH_UTILITY_ZH], actionMouse[LENGTH_UTILITY_ZH]; 267 | float startPos[DATA_DIM], startAngle[DATA_DIM], velocity[DATA_DIM]; 268 | float throwPos[DATA_DIM]; 269 | char trueUtId[LENGTH_UTILITY_ID]; 270 | 271 | detail_json.GetString("id", utId, sizeof(utId)); 272 | detail_json.GetString("utility_id", trueUtId, sizeof(trueUtId)); 273 | detail_json.GetString("type", utType, sizeof(utType)); 274 | detail_json.GetString("title", utTitle, sizeof(utTitle)); 275 | detail_json.GetString("brief", utBrief, sizeof(utBrief)); 276 | detail_json.GetString("author", author, sizeof(author)); 277 | detail_json.GetString("action_body", actionBody, sizeof(actionBody)); 278 | detail_json.GetString("action_mouse", actionMouse, sizeof(actionMouse)); 279 | startPos[0] = detail_json.GetFloat("start_x"); 280 | startPos[1] = detail_json.GetFloat("start_y"); 281 | startPos[2] = detail_json.GetFloat("start_z"); 282 | startAngle[0] = detail_json.GetFloat("aim_pitch"); 283 | startAngle[1] = detail_json.GetFloat("aim_yaw"); 284 | startAngle[2] = 0.0; 285 | velocity[0] = detail_json.GetFloat("velocity_x"); 286 | velocity[1] = detail_json.GetFloat("velocity_y"); 287 | velocity[2] = detail_json.GetFloat("velocity_z"); 288 | throwPos[0] = detail_json.GetFloat("throw_x"); 289 | throwPos[1] = detail_json.GetFloat("throw_y"); 290 | throwPos[2] = detail_json.GetFloat("throw_z"); 291 | 292 | // set last ut record 293 | // clear pre-recfile 294 | if (!StrEqual(g_aLastUtilityId[client], trueUtId)) { 295 | bool candelete = true; 296 | for (int i = 0; i <= MaxClients; i++) { 297 | if (IsPlayer(i) && i != client && StrEqual(g_aLastUtilityId[client], g_aLastUtilityId[i])) { 298 | candelete = false; 299 | break; 300 | } 301 | } 302 | if (candelete) { 303 | DeleteReplayFileFromUtid(g_aLastUtilityId[client]); 304 | } 305 | strcopy(g_aLastUtilityId[client], LENGTH_UTILITY_ID, trueUtId); 306 | } 307 | 308 | if (!StrEqual(g_aLastArticleId[client], utId)) { 309 | strcopy(g_aLastArticleId[client], LENGTH_UTILITY_ID, utId); 310 | } 311 | // decode ut name 312 | char utNameZh[LENGTH_UTILITY_ZH], utWeaponCmd[LENGTH_UTILITY_ZH]; 313 | Utility_TinyName2Zh(utType, "%s", utNameZh); 314 | Utility_TinyName2Weapon(utType, utWeaponCmd, client); 315 | // tp player and get utility 316 | TeleportEntity(client, startPos, startAngle, NULL_VECTOR); 317 | GivePlayerItem(client, utWeaponCmd); 318 | Format(utWeaponCmd, sizeof(utWeaponCmd), "use %s", utWeaponCmd); 319 | SetEntProp(client, Prop_Send, "m_iAmmo", 1); 320 | FakeClientCommand(client, utWeaponCmd); 321 | // auto throw 322 | if (g_bAutoThrow[client]) { 323 | if (!StartRequestReplayFile(client, utId, trueUtId)) { 324 | if (velocity[0] == 0.0 && velocity[1] == 0.0 && velocity[2] == 0.0) { 325 | PrintToChat(client, "%s \x06当前道具没有记录初始速度,无法自动投掷", PREFIX); 326 | } 327 | else { 328 | GrenadeType grenadeType = TinyName_2_GrenadeType(utType, client); 329 | CSU_ThrowGrenade(client, grenadeType, throwPos, velocity); 330 | PrintToChat(client, "%s \x05已自动投掷道具", PREFIX); 331 | } 332 | } 333 | else { 334 | // cache utility init velocity & throw pos 335 | g_aUtilityVelocity[client][0] = velocity[0]; 336 | g_aUtilityVelocity[client][1] = velocity[1]; 337 | g_aUtilityVelocity[client][2] = velocity[2]; 338 | g_aThrowPositions[client][0] = throwPos[0]; 339 | g_aThrowPositions[client][1] = throwPos[1]; 340 | g_aThrowPositions[client][2] = throwPos[2]; 341 | g_aStartPositions[client][0] = startPos[0]; 342 | g_aStartPositions[client][1] = startPos[1]; 343 | g_aStartPositions[client][2] = startPos[2]; 344 | g_aStartAngles[client][0] = startAngle[0]; 345 | g_aStartAngles[client][1] = startAngle[1]; 346 | g_aStartAngles[client][2] = startAngle[2]; 347 | } 348 | } 349 | 350 | // printout 351 | PrintToChat(client, "\x09 ------------------------------------- "); 352 | PrintToChat(client, "%s ID: \x10%s", PREFIX, utId); 353 | PrintToChat(client, "%s 名称: \x10%s", PREFIX, utTitle); 354 | if (strlen(utBrief) != 0 && !StrEqual(utTitle, utBrief)) 355 | PrintToChat(client, "%s 简介: \x10%s", PREFIX, utBrief); 356 | PrintToChat(client, "%s 种类: \x10%s", PREFIX, utNameZh); 357 | if (strlen(author) != 0) 358 | PrintToChat(client, "%s 作者: \x10%s", PREFIX, author); 359 | PrintToChat(client, "\x09 ------------------------------------- "); 360 | // 361 | PrintCenterText(client, "身体动作:%s\n鼠标动作:%s\n", actionBody, actionMouse); 362 | } -------------------------------------------------------------------------------- /scripting/csgowiki/utils.sp: -------------------------------------------------------------------------------- 1 | // check handle function on/off 2 | bool check_function_on(Handle: ghandle, char[] errorMsg, client = -1) { 3 | bool benable = GetConVarBool(ghandle) && GetConVarBool(g_hCSGOWikiEnable); 4 | if (!benable && client != -1) { 5 | PrintToChat(client, "%s %s", PREFIX, errorMsg); 6 | } 7 | return benable; 8 | } 9 | 10 | // check player valid 11 | stock bool IsPlayer(int client) { 12 | return IsValidClient(client) && !IsFakeClient(client) && !IsClientSourceTV(client); 13 | } 14 | 15 | stock bool IsValidClient(int client) { 16 | return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); 17 | } 18 | 19 | 20 | int GetServerTickrate() { 21 | return RoundToZero(1.0 / GetTickInterval()); 22 | } 23 | 24 | // convar handle function 25 | Handle FindOrCreateConvar(char[] cvName, char[] cvDefault, char[] cvDescription, float fMin=-1.0, float fMax=-1.0, bool flag=false) { 26 | Handle cvHandle = FindConVar(cvName); 27 | if (cvHandle == INVALID_HANDLE) { 28 | if (fMin == -1.0 && fMax == -1.0) 29 | if (flag) 30 | cvHandle = CreateConVar(cvName, cvDefault, cvDescription, FCVAR_PROTECTED); 31 | else 32 | cvHandle = CreateConVar(cvName, cvDefault, cvDescription); 33 | else if (fMin != -1.0 && fMax != -1.0) 34 | if (flag) 35 | cvHandle = CreateConVar(cvName, cvDefault, cvDescription, FCVAR_PROTECTED, true, fMin, true, fMax); 36 | else 37 | cvHandle = CreateConVar(cvName, cvDefault, cvDescription, _, true, fMin, true, fMax); 38 | else return INVALID_HANDLE; 39 | } 40 | return cvHandle; 41 | } 42 | 43 | void HookOpConVarChange() { 44 | HookConVarChange(g_hCSGOWikiEnable, ConVar_CSGOWikiEnableChange); 45 | HookConVarChange(g_hOnUtilitySubmit, ConVar_OnUtilitySubmitChange); 46 | HookConVarChange(g_hOnUtilityWiki, ConVar_OnUtilityWikiChange); 47 | } 48 | 49 | public ConVar_CSGOWikiEnableChange(Handle:convar, const String:oldValue[], const String:newValue[]) { 50 | if (GetConVarBool(g_hCSGOWikiEnable)) { 51 | PrintToChatAll("%s \x09CSGOWiki插件总功能\x01 => \x04已开启", PREFIX); 52 | } 53 | else { 54 | PrintToChatAll("%s \x09CSGOWiki插件总功能\x01 => \x02已关闭", PREFIX); 55 | } 56 | } 57 | 58 | public ConVar_OnUtilitySubmitChange(Handle:convar, const String:oldValue[], const String:newValue[]) { 59 | if (GetConVarBool(g_hOnUtilitySubmit)) { 60 | PrintToChatAll("%s \x09道具上传功能\x01 => \x04已开启", PREFIX); 61 | } 62 | else { 63 | PrintToChatAll("%s \x09道具上传功能\x01 => \x02已关闭", PREFIX); 64 | } 65 | } 66 | 67 | public ConVar_OnUtilityWikiChange(Handle:convar, const String:oldValue[], const String:newValue[]) { 68 | if (GetConVarBool(g_hOnUtilityWiki)) { 69 | PrintToChatAll("%s \x09道具学习功能\x01 => \x04已开启", PREFIX); 70 | } 71 | else { 72 | PrintToChatAll("%s \x09道具学习功能\x01 => \x02已关闭", PREFIX); 73 | } 74 | } 75 | 76 | // utils for utility submit 77 | void GrenadeType_2_Tinyname(GrenadeType utCode, char[] utTinyName) { 78 | switch (utCode) { 79 | case GrenadeType_HE: 80 | strcopy(utTinyName, LENGTH_UTILITY_TINY, "grenade"); 81 | case GrenadeType_Flash: 82 | strcopy(utTinyName, LENGTH_UTILITY_TINY, "flash"); 83 | case GrenadeType_Smoke: 84 | strcopy(utTinyName, LENGTH_UTILITY_TINY, "smoke"); 85 | case GrenadeType_Molotov: 86 | strcopy(utTinyName, LENGTH_UTILITY_TINY, "molotov"); 87 | case GrenadeType_Incendiary: 88 | strcopy(utTinyName, LENGTH_UTILITY_TINY, "molotov"); 89 | } 90 | } 91 | 92 | void Action_Int2Array(client, bool[] wikiAction) { 93 | for (new idx = 0; idx < CSGO_ACTION_NUM; idx++) { 94 | if (g_aActionRecord[client] & (1 << idx)) { 95 | switch(g_aCsgoActionMap[idx]) { 96 | case IN_JUMP: wikiAction[e_wJump] = true; 97 | case IN_DUCK: wikiAction[e_wDuck] = true; 98 | case IN_ATTACK: wikiAction[e_wLeftclick] = true; 99 | case IN_ATTACK2: wikiAction[e_wRightclick] = true; 100 | case IN_MOVELEFT: wikiAction[e_wRun] = true; 101 | case IN_MOVERIGHT: wikiAction[e_wRun] = true; 102 | case IN_BACK: wikiAction[e_wRun] = true; 103 | case IN_FORWARD: wikiAction[e_wRun] = true; 104 | case IN_SPEED: wikiAction[e_wWalk] = true; 105 | } 106 | } 107 | } 108 | // post fix 109 | if (!wikiAction[e_wRun] && wikiAction[e_wWalk]) { 110 | wikiAction[e_wWalk] = false; // 没有移动只按shift 111 | } 112 | if (wikiAction[e_wRun] && wikiAction[e_wWalk]) { 113 | wikiAction[e_wRun] = false; // just shift 114 | } 115 | if (wikiAction[e_wRun] && wikiAction[e_wDuck]) { 116 | wikiAction[e_wWalk] = true; 117 | wikiAction[e_wRun] = false; 118 | } 119 | if (!(wikiAction[e_wRun] || wikiAction[e_wWalk] 120 | || wikiAction[e_wJump] || wikiAction[e_wDuck])) { 121 | wikiAction[e_wStand] = true; 122 | } 123 | } 124 | 125 | void Action_Int2Str(client, char[] strAction) { 126 | bool wikiAction[CSGOWIKI_ACTION_NUM] = {}; 127 | Action_Int2Array(client, wikiAction); 128 | char StrTemp[CSGOWIKI_ACTION_NUM][6] = { 129 | "跳 ", "蹲 ", "跑 ", "走 ", "站 ", "左键 ", "右键 " 130 | }; 131 | for (new idx = 0; idx < CSGOWIKI_ACTION_NUM; idx ++) { 132 | if (!wikiAction[idx]) continue; 133 | StrCat(strAction, LENGTH_MESSAGE, StrTemp[idx]); 134 | } 135 | } 136 | 137 | void TicktagGenerate(char[] tickTag, const bool[] wikiAction) { 138 | strcopy(tickTag, LENGTH_STATUS, "64/128"); 139 | if (wikiAction[e_wJump]) { 140 | IntToString(g_iServerTickrate, tickTag, LENGTH_STATUS); 141 | } 142 | } 143 | 144 | void Utility_TinyName2Zh(char[] utTinyName, char[] format, char[] zh) { 145 | if (StrEqual(utTinyName, "smoke")) { 146 | Format(zh, LENGTH_UTILITY_ZH, format, "烟雾弹"); 147 | } 148 | else if (StrEqual(utTinyName, "grenade")) { 149 | Format(zh, LENGTH_UTILITY_ZH, format, "手雷"); 150 | } 151 | else if (StrEqual(utTinyName, "flash")) { 152 | Format(zh, LENGTH_UTILITY_ZH, format, "闪光弹"); 153 | } 154 | else if (StrEqual(utTinyName, "molotov")) { 155 | Format(zh, LENGTH_UTILITY_ZH, format, "燃烧弹"); 156 | } 157 | } 158 | 159 | void Utility_FullName2Zh(char[] utFullName, char[] format, char[] zh) { 160 | if (StrEqual(utFullName, "smokegrenade")) { 161 | Format(zh, LENGTH_UTILITY_ZH, format, "烟雾弹"); 162 | } 163 | else if (StrEqual(utFullName, "hegrenade")) { 164 | Format(zh, LENGTH_UTILITY_ZH, format, "手雷"); 165 | } 166 | else if (StrEqual(utFullName, "flashbang")) { 167 | Format(zh, LENGTH_UTILITY_ZH, format, "闪光弹"); 168 | } 169 | else if (StrEqual(utFullName, "molotov")) { 170 | Format(zh, LENGTH_UTILITY_ZH, format, "燃烧弹"); 171 | } 172 | else if (StrEqual(utFullName, "incgrenade")) { 173 | Format(zh, LENGTH_UTILITY_ZH, format, "燃烧瓶"); 174 | } 175 | } 176 | 177 | void Utility_TinyName2Weapon(char[] utTinyName, char[] weaponName, client) { 178 | if (StrEqual(utTinyName, "smoke") || StrEqual(utTinyName, "smokegrenade")) { 179 | strcopy(weaponName, LENGTH_UTILITY_ZH, "weapon_smokegrenade"); 180 | } 181 | else if (StrEqual(utTinyName, "grenade") || StrEqual(utTinyName, "hegrenade")) { 182 | strcopy(weaponName, LENGTH_UTILITY_ZH, "weapon_hegrenade"); 183 | } 184 | else if (StrEqual(utTinyName, "flash") || StrEqual(utTinyName, "flashbang")) { 185 | strcopy(weaponName, LENGTH_UTILITY_ZH, "weapon_flashbang"); 186 | } 187 | else if (StrEqual(utTinyName, "molotov") || StrEqual(utTinyName, "incgrenade")) { 188 | new teamFlag = GetClientTeam(client); 189 | if (CS_TEAM_T == teamFlag) { 190 | strcopy(weaponName, LENGTH_UTILITY_ZH, "weapon_molotov"); 191 | } 192 | else if (CS_TEAM_CT == teamFlag){ // [TODO] spec 193 | strcopy(weaponName, LENGTH_UTILITY_ZH, "weapon_incgrenade"); 194 | } 195 | } 196 | } 197 | 198 | GrenadeType TinyName_2_GrenadeType(char[] utTinyName, client) { 199 | if (StrEqual(utTinyName, "smoke") || StrEqual(utTinyName, "smokegrenade")) { 200 | return GrenadeType_Smoke; 201 | } 202 | else if (StrEqual(utTinyName, "grenade") || StrEqual(utTinyName, "hegrenade")) { 203 | return GrenadeType_HE; 204 | } 205 | else if (StrEqual(utTinyName, "flash") || StrEqual(utTinyName, "flashbang")) { 206 | return GrenadeType_Flash; 207 | } 208 | else if (StrEqual(utTinyName, "molotov") || StrEqual(utTinyName, "incgrenade")) { 209 | new teamFlag = GetClientTeam(client); 210 | if (CS_TEAM_T == teamFlag) { 211 | return GrenadeType_Molotov; 212 | } 213 | else if (CS_TEAM_CT == teamFlag){ // [TODO] spec 214 | return GrenadeType_Incendiary; 215 | } 216 | } 217 | return GrenadeType_None; 218 | } 219 | 220 | 221 | void ResetReqLock(pclient = -1) { 222 | if (pclient != -1) { 223 | g_aReqLock[pclient] = false; 224 | return; 225 | } 226 | for (new client = 0; client <= MAXPLAYERS; client++) { 227 | g_aReqLock[client] = false; 228 | } 229 | } 230 | 231 | 232 | // ----------------- server monitor json generator ------- 233 | // JSONArray encode_json_server_monitor(int exclient, bool inctoken=true, bool authType=true, bool incmap=false, bool incid=false) { 234 | // JSONArray monitor_json = new JSONArray(); 235 | // if (inctoken) { 236 | // char token[LENGTH_TOKEN]; 237 | // GetConVarString(g_hCSGOWikiToken, token, LENGTH_TOKEN); 238 | // monitor_json.PushString(token); 239 | // } 240 | // if (exclient == -1) { 241 | // monitor_json.Push(new JSONArray()); 242 | // return monitor_json; 243 | // } 244 | // if (incmap) { 245 | // monitor_json.PushString(g_sCurrentMap); 246 | // } 247 | // for (int client_id = 0; client_id <= MaxClients; client_id++) { 248 | // if(!IsPlayer(client_id) || client_id == exclient) continue; 249 | // char client_name[LENGTH_NAME], steamid[LENGTH_STEAMID64], str_ping[4]; 250 | // GetClientName(client_id, client_name, LENGTH_NAME); 251 | // if (authType) { 252 | // GetClientAuthId(client_id, AuthId_SteamID64, steamid, LENGTH_STEAMID64) 253 | // } else { 254 | // GetClientAuthId(client_id, AuthId_Steam2, steamid, LENGTH_STEAMID64) 255 | // } 256 | // float latency = GetClientAvgLatency(client_id, NetFlow_Both); 257 | // IntToString(RoundToNearest(latency * 500), str_ping, sizeof(str_ping)); 258 | // // json encode 259 | // JSONArray client_arr = new JSONArray(); 260 | // if (incid) { 261 | // client_arr.PushInt(client_id); 262 | // } 263 | // client_arr.PushString(client_name); 264 | // client_arr.PushString(steamid); 265 | // client_arr.PushString(str_ping); 266 | // monitor_json.Push(client_arr); 267 | // } 268 | // return monitor_json; 269 | // } 270 | 271 | // ----------------- check version ---------------------- 272 | void PluginVersionHint(client) { 273 | if (StrEqual(g_sLatestVersion, "")) { 274 | PrintToChat(client, "%s 获取版本信息失败:[\x02%s\x01]", PREFIX, g_sLatestInfo); 275 | } 276 | else if (StrEqual(g_sCurrentVersion, g_sLatestVersion)) { 277 | PrintToChat(client, "%s 当前csgowiki插件已为最新版本<\x09%s\x01>", PREFIX, g_sCurrentVersion); 278 | } 279 | else { 280 | PrintToChat(client, "%s 当前服务器csgowiki插件版本<\x0F%s\x01>,最新版本为<\x09%s\x01>", PREFIX, g_sCurrentVersion, g_sLatestVersion); 281 | PrintToChat(client, "%s \x06%s\x01", PREFIX, g_sLatestInfo); 282 | PrintToChat(client, "%s 请及时更新插件避免已有功能失效", PREFIX); 283 | } 284 | } 285 | 286 | void PluginVersionCheck(client = -1) { 287 | GetPluginInfo(INVALID_HANDLE, PlInfo_Version, g_sCurrentVersion, LENGTH_VERSION); 288 | HTTPRequest PluginVersionCheckRequest = new HTTPRequest( 289 | "https://api.github.com/repos/hx-w/CSGOWiki-Plugins/releases/latest" 290 | ); 291 | PluginVersionCheckRequest.SetHeader("User-Agent", "request"); 292 | PluginVersionCheckRequest.Get(PluginVersionCheckCallback, client); 293 | } 294 | 295 | void PluginVersionCheckCallback(HTTPResponse response, int client) { 296 | if (response.Status == HTTPStatus_OK) { 297 | JSONObject resp_json = view_as(response.Data); 298 | resp_json.GetString("tag_name", g_sLatestVersion, sizeof(g_sLatestVersion)); 299 | resp_json.GetString("name", g_sLatestInfo, sizeof(g_sLatestInfo)); 300 | delete resp_json; 301 | } 302 | else { 303 | g_sLatestInfo = "github-api访问失败"; 304 | } 305 | if (client != -1) { 306 | PluginVersionHint(client); 307 | } 308 | } 309 | 310 | public bool EnforceDirExists(const char[] smPath) { 311 | char dir[PLATFORM_MAX_PATH + 1]; 312 | BuildPath(Path_SM, dir, sizeof(dir), smPath); 313 | if (!DirExists(dir)) { 314 | if (!CreateDirectory(dir, 511)) { 315 | LogError("Failed to create dir: %s", dir); 316 | return false; 317 | } 318 | } 319 | return true; 320 | } 321 | 322 | void ClearPlayerProMatchInfo(client) { 323 | if (IsPlayer(client)) { 324 | g_aProMatchIndex[client] = -1; 325 | } 326 | } 327 | 328 | // ----------------- hint color message fix -------------- 329 | UserMsg g_TextMsg, g_HintText, g_KeyHintText; 330 | static char g_sSpace[1024]; 331 | 332 | void HintColorMessageFixStart() { 333 | for(int i = 0; i < sizeof g_sSpace - 1; i++) { 334 | g_sSpace[i] = ' '; 335 | } 336 | 337 | g_TextMsg = GetUserMessageId("TextMsg"); 338 | g_HintText = GetUserMessageId("HintText"); 339 | g_KeyHintText = GetUserMessageId("KeyHintText"); 340 | 341 | HookUserMessage(g_TextMsg, TextMsgHintTextHook, true); 342 | HookUserMessage(g_HintText, TextMsgHintTextHook, true); 343 | HookUserMessage(g_KeyHintText, TextMsgHintTextHook, true); 344 | } 345 | 346 | Action TextMsgHintTextHook(UserMsg msg_id, Protobuf msg, const int[] players, int playersNum, bool reliable, bool init) { 347 | static char sBuf[sizeof(g_sSpace)]; 348 | if(msg_id == g_HintText) { 349 | msg.ReadString("text", sBuf, sizeof(sBuf)); 350 | } 351 | else if(msg_id == g_KeyHintText) { 352 | msg.ReadString("hints", sBuf, sizeof(sBuf), 0); 353 | } 354 | else if(msg.ReadInt("msg_dst") == 4) { 355 | msg.ReadString("params", sBuf, sizeof(sBuf), 0); 356 | } 357 | else { 358 | return Plugin_Continue; 359 | } 360 | 361 | if(StrContains(sBuf, "(StartMessageEx(g_TextMsg, newClients, newTotal, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS)); 402 | 403 | if(hMessage) { 404 | hMessage.SetInt("msg_dst", 4); 405 | hMessage.AddString("params", "#SFUI_ContractKillStart"); 406 | 407 | Format(sBuf, sizeof sBuf, "%s%s", sBuf, g_sSpace); 408 | hMessage.AddString("params", sBuf); 409 | 410 | hMessage.AddString("params", NULL_STRING); 411 | hMessage.AddString("params", NULL_STRING); 412 | hMessage.AddString("params", NULL_STRING); 413 | hMessage.AddString("params", NULL_STRING); 414 | 415 | EndMessage(); 416 | } 417 | } -------------------------------------------------------------------------------- /scripting/include/botmimic_fix.inc: -------------------------------------------------------------------------------- 1 | #if defined _botmimic_included 2 | #endinput 3 | #endif 4 | #define _botmimic_included 5 | 6 | #define MAX_RECORD_NAME_LENGTH 64 7 | #define MAX_BOOKMARK_NAME_LENGTH 64 8 | #define DEFAULT_CATEGORY "default" 9 | 10 | enum BMError { 11 | BM_NoError = 0, 12 | BM_BadClient, // Provided client index is invalid 13 | BM_FileNotFound, // The file does not exists or can't be opened 14 | BM_BadFile, // Not a Bot Mimic record. 15 | BM_NewerBinaryVersion // The record was recorded with a newer version of Bot Mimic and can't be played. 16 | }; 17 | 18 | enum struct BMFileHeader { 19 | int BMFH_binaryFormatVersion; 20 | int BMFH_recordEndTime; 21 | char BMFH_recordName[MAX_RECORD_NAME_LENGTH]; 22 | int BMFH_tickCount; 23 | float BMFH_initialPosition[3]; 24 | float BMFH_initialAngles[3]; 25 | int BMFH_bookmarkCount; 26 | } 27 | 28 | /** 29 | * Start to record the movements of a player. 30 | * It's stored in memory until told to write to disk. 31 | * 32 | * Make sure the player isn't recording already. 33 | * 34 | * @param client The client to record 35 | * @param name The name of the record (anything, not the filename) 36 | * @param category The category to put this record in. This is used as a directory filename inside /data/botmimic/%CATEGORY%/%MAP_NAME%/stuff.rec 37 | * @param subdir The subdirectory to organize records physically. This isn't used or retrieved back anywhere, just to better manage files by hand. /data/botmimic/%CATEGORY%/%MAP_NAME%/%SUBDIR%/stuff.rec 38 | */ 39 | native void BotMimicFix_StartRecording(int client, const char[] name, const char[] category = "", const char[] subdir = ""); 40 | 41 | /** 42 | * Pause recording the current record. 43 | * 44 | * @param client The recording client, which should pause recording. 45 | * @error Invalid client index, client not recording or recording already paused. 46 | */ 47 | native void BotMimicFix_PauseRecording(int client); 48 | 49 | /** 50 | * Resume recording the current record. 51 | * 52 | * @param client The recording client, which should resume recording. 53 | * @error Invalid client index, client not recording or record not paused. 54 | */ 55 | native void BotMimicFix_ResumeRecording(int client); 56 | 57 | /** 58 | * Check whether a client is currently paused recording a record. 59 | * 60 | * @param client The client index of the player you want to know if he's paused. 61 | * @return True if recording is paused, false otherwise. 62 | * @error Invalid client index or client not recording. 63 | */ 64 | native bool BotMimicFix_IsRecordingPaused(int client); 65 | 66 | /** 67 | * Stop recording and save or discard the record 68 | * 69 | * @param client The client which was recording 70 | * @param save Save the record (true) or discard (false) 71 | * @param filename The filename saving(without .rec), timestamp for default 72 | */ 73 | native void BotMimicFix_StopRecording(int client, bool save = true, const char[] filename=""); 74 | 75 | /** 76 | * Save the current frame with the given name as bookmark. 77 | * You can skip to this point when playing back the record using BotMimicFix_GoToBookmark. 78 | * 79 | * @param client The client which is recording 80 | * @param name The name of this bookmark 81 | * @noreturn 82 | * @error Client not recording 83 | */ 84 | native void BotMimicFix_SaveBookmark(int client, const char[] name); 85 | 86 | /** 87 | * Deletes a record and does some checks, that the file is really a record. 88 | * 89 | * @param path The Path to the .rec recording file to delete. 90 | * @return Number of bots, which were mimicing this record or -1 on error (file not found/invalid) 91 | */ 92 | native int BotMimicFix_DeleteRecord(const char[] path); 93 | 94 | /** 95 | * Is the player currently recording something? 96 | * 97 | * @param client The client to check 98 | * @return true, if player is recording, false otherwise 99 | */ 100 | native bool BotMimicFix_IsPlayerRecording(int client); 101 | 102 | /** 103 | * Is the player currently mimicing something? 104 | * 105 | * @param client The client to check 106 | * @return true, if the player is mimicing, false otherwise 107 | */ 108 | native bool BotMimicFix_IsPlayerMimicing(int client); 109 | 110 | /** 111 | * Get the path to the record file this player is currently mimicing. 112 | * 113 | * @param client The mimicing client 114 | * @param path A String where to store the path 115 | * @param maxlen The maximal length of the path 116 | */ 117 | native void BotMimicFix_GetRecordPlayerMimics(int client, char[] path, int maxlen); 118 | 119 | /** 120 | * Let a client start to mimic a record from a file. 121 | * 122 | * @param client The client, which should start mimicing 123 | * @param path The path to a .rec recording file 124 | * @return BM_NoError if all went smooth, see BMError definition. 125 | */ 126 | native BMError BotMimicFix_PlayRecordFromFile(int client, const char[] path); 127 | 128 | /** 129 | * Let a client start to mimic a record by providing the record name. 130 | * Since record names don't have to be unique, this native picks the most recent one. 131 | * 132 | * @param client The client, which should start mimicing. 133 | * @param name The name of the record to play. 134 | * @return BM_NoError if all went smooth, see BMError definition. 135 | */ 136 | native BMError BotMimicFix_PlayRecordByName(int client, const char[] name); 137 | 138 | /** 139 | * Have a bot restart the record he's currently playing from the beginning. 140 | * 141 | * @param client The client, who should start over with the record he's currently mimicing. 142 | */ 143 | native void BotMimicFix_ResetPlayback(int client); 144 | 145 | /** 146 | * Jump the the frame where this bookmark was set in the record. 147 | * @see BotMimicFix_SaveBookmark 148 | * 149 | * @param client The client, which is mimicing some record 150 | * @param name The name of the bookmark saved during recording using BotMimicFix_SaveBookmark 151 | */ 152 | native void BotMimicFix_GoToBookmark(int client, const char[] name); 153 | 154 | /** 155 | * Stops a player from mimicing a record. 156 | * 157 | * @param client The client who should stop mimicing 158 | */ 159 | native void BotMimicFix_StopPlayerMimic(int client); 160 | 161 | /** 162 | * Get the Handle to a sorted adt_array, containing a list of paths to all loaded record files. 163 | * DON'T CLOSE THIS HANDLE! 164 | * Just use GetArrayString to read the path. 165 | * 166 | * @return Handle to sorted adt_array containing all paths to records 167 | */ 168 | native ArrayList BotMimicFix_GetLoadedRecordList(); 169 | 170 | /** 171 | * Get the Handle to a sorted adt_array, containing a list of categorys. 172 | * DON'T CLOSE THIS HANDLE! 173 | * Just use GetArrayString to read the category. 174 | * 175 | * @return Handle to sorted adt_array containing all categories. 176 | */ 177 | native ArrayList BotMimicFix_GetLoadedRecordCategoryList(); 178 | 179 | /** 180 | * Get the header information of a record. This includes the record name. 181 | * 182 | * @param path The path to the .rec record file 183 | * @param iFileHeader An array to store the file header in. 184 | * @return BM_NoError if all went smooth, see BMError definition. 185 | */ 186 | native BMError BotMimicFix_GetFileHeaders(const char[] path, any iFileHeader, int size); 187 | 188 | /** 189 | * Get the category of a record. 190 | * 191 | * @param path The path to the .rec record file. 192 | * @param category The String where to store the category in. 193 | * @param maxlen The maximal length of the category buffer. 194 | * @return true if category of file found, false otherwise 195 | */ 196 | native bool BotMimicFix_GetFileCategory(const char[] path, char[] category, int maxlen); 197 | 198 | /** 199 | * Change the name of a record. This doesn't change the filename, but the stored record name inside the file. (BMTP_recordName) 200 | * 201 | * @param path The path to the .rec record file which name to change. 202 | * @param name The new name of the record 203 | * @return BM_NoError if all went smooth, see BMError definition. 204 | */ 205 | native BMError BotMimicFix_ChangeRecordName(const char[] path, char[] name); 206 | 207 | /** 208 | * Get a list of all bookmarks stored in this record as an adt_array. 209 | * You have to close the returned Handle using CloseHandle. 210 | * 211 | * @param path The path to the .rec record file. 212 | * @param bookmarks The handle where the bookmark array will be stored in. 213 | * @return BM_NoError if all went smooth, see BMError definition. 214 | */ 215 | native BMError BotMimicFix_GetRecordBookmarks(const char[] path, ArrayList &bookmarks); 216 | 217 | /** 218 | * Called when a player starts recording. 219 | * path is NOT the path to the .rec file, but just the path to the category folder (by default: Path_SM/data/botmimic/%CATEGORY%) 220 | * 221 | * @param client The client index, who's being recorded 222 | * @param name The name of the recording (stored in file header) 223 | * @param category The category name 224 | * @param subdir The subdir used to organize the record files (no further sense..) 225 | * @param path The path to the category folder 226 | * @return >= Plugin_Handled to abort recording or Plugin_Continue to let it pass and start recording. 227 | */ 228 | forward Action BotMimicFix_OnStartRecording(int client, char[] name, char[] category, char[] subdir, char[] path); 229 | 230 | /** 231 | * Called when recording a record is paused or resumed. 232 | * 233 | * @param client The client which recording pause state changed 234 | * @param paused True when the recording was paused, false when it was unpaused 235 | */ 236 | forward void BotMimicFix_OnRecordingPauseStateChanged(int client, bool paused); 237 | 238 | /** 239 | * Called when a bookmark is saved while the client is recording. 240 | * 241 | * @param client The client which is recording. 242 | * @param bookmark The name of the saved bookmark. 243 | * @noreturn 244 | */ 245 | forward void BotMimicFix_OnRecordingBookmarkSaved(int client, const char[] bookmark); 246 | 247 | /** 248 | * Called when a player stops recording. 249 | * Change the save param if you want to prevent it from being discarded/written. 250 | * 251 | * @param client The client who was recording. 252 | * @param name The name of the record (stored in file header) 253 | * @param category The category name. 254 | * @param subdir The subdir used to organize the record files (no further sense..) 255 | * @param path The path to the category folder 256 | * @param save Set to true, if the record should be stored to disk, or false to discard. 257 | * @return >= Plugin_Handled to continue recording, Plugin_Continue to let it stop. 258 | */ 259 | forward Action BotMimicFix_OnStopRecording(int client, char[] name, char[] category, char[] subdir, char[] path, bool &save); 260 | 261 | /** 262 | * Called when a record was saved to file. 263 | * 264 | * @param client The client who was recording. 265 | * @param name The name of the record (stored in file header) 266 | * @param category The category name. 267 | * @param subdir The subdir used to organize the record files (no further sense..) 268 | * @param file The actual path to the saved .rec file. 269 | */ 270 | forward void BotMimicFix_OnRecordSaved(int client, char[] name, char[] category, char[] subdir, char[] file); 271 | 272 | /** 273 | * Called when a record was deleted. 274 | * 275 | * @param name The name of the record (stored in file header) 276 | * @param category The category of the file. (If it wasn't loaded before it defaults to "default".) 277 | * @param path The path to the deleted file. 278 | */ 279 | forward void BotMimicFix_OnRecordDeleted(char[] name, char[] category, char[] path); 280 | 281 | /** 282 | * Called when a player starts to mimic a record 283 | * 284 | * @param client The client which starts mimicing. 285 | * @param name The name of the record (stored in file header) 286 | * @param category The category of the file. 287 | * @param path The path to the record file. 288 | * @return >= Plugin_Handled to stop the player from mimicing, Plugin_Continue to allow 289 | */ 290 | forward Action BotMimicFix_OnPlayerStartsMimicing(int client, char[] name, char[] category, char[] path); 291 | 292 | /** 293 | * Called when a player stops mimicing a record. 294 | * 295 | * @param client The client who was mimicing 296 | * @param name The name of the record (stored in file header) 297 | * @param category The category of the file. 298 | * @param path The path to the record file. 299 | */ 300 | forward void BotMimicFix_OnPlayerStopsMimicing(int client, char[] name, char[] category, char[] path); 301 | 302 | /** 303 | * Called everytime a mimicing player starts to mimic the record again from the beginning, 304 | * when he was teleported back to the start. 305 | * 306 | * @param client The mimicing client 307 | */ 308 | forward void BotMimicFix_OnPlayerMimicLoops(int client); 309 | 310 | /** 311 | * Called when a bookmark is reached during playback of a record. 312 | * 313 | * @param client The client which is mimicing. 314 | * @param bookmark The name of the bookmark. 315 | */ 316 | forward void BotMimicFix_OnPlayerMimicBookmark(int client, const char[] bookmark); 317 | 318 | /** 319 | * Translate an error id to a human readable string 320 | * 321 | * @param error The error id 322 | * @param str The string to store the error message in 323 | * @param maxlen The maximal length of the error message string 324 | */ 325 | stock void BotMimicFix_GetErrorString(BMError error, char[] str, int maxlen) 326 | { 327 | switch(error) 328 | { 329 | case BM_BadClient: 330 | { 331 | strcopy(str, maxlen, "Invalid client index."); 332 | } 333 | case BM_FileNotFound: 334 | { 335 | strcopy(str, maxlen, "File not found."); 336 | } 337 | case BM_NewerBinaryVersion: 338 | { 339 | strcopy(str, maxlen, "The file was recorded with a newer version of Bot Mimic and can't be played."); 340 | } 341 | case BM_BadFile: 342 | { 343 | strcopy(str, maxlen, "The file is not a record. Bad format."); 344 | } 345 | case BM_NoError: 346 | { 347 | strcopy(str, maxlen, ""); 348 | } 349 | } 350 | } 351 | 352 | public SharedPlugin __pl_botmimic = 353 | { 354 | name = "botmimic_fix", 355 | file = "botmimic_fix.smx", 356 | #if defined REQUIRE_PLUGIN 357 | required = 1 358 | #else 359 | required = 0 360 | #endif 361 | }; 362 | 363 | #if !defined REQUIRE_PLUGIN 364 | public void __pl_botmimic_SetNTVOptional() 365 | { 366 | MarkNativeAsOptional("BotMimicFix_StartRecording"); 367 | MarkNativeAsOptional("BotMimicFix_PauseRecording"); 368 | MarkNativeAsOptional("BotMimicFix_ResumeRecording"); 369 | MarkNativeAsOptional("BotMimicFix_IsRecordingPaused"); 370 | MarkNativeAsOptional("BotMimicFix_StopRecording"); 371 | MarkNativeAsOptional("BotMimicFix_SaveBookmark"); 372 | MarkNativeAsOptional("BotMimicFix_GoToBookmark"); 373 | MarkNativeAsOptional("BotMimicFix_DeleteRecord"); 374 | MarkNativeAsOptional("BotMimicFix_IsPlayerRecording"); 375 | MarkNativeAsOptional("BotMimicFix_IsPlayerMimicing"); 376 | MarkNativeAsOptional("BotMimicFix_GetRecordPlayerMimics"); 377 | MarkNativeAsOptional("BotMimicFix_PlayRecordFromFile"); 378 | MarkNativeAsOptional("BotMimicFix_ResetPlayback"); 379 | MarkNativeAsOptional("BotMimicFix_PlayRecordByName"); 380 | MarkNativeAsOptional("BotMimicFix_StopPlayerMimic"); 381 | MarkNativeAsOptional("BotMimicFix_GetLoadedRecordCategoryList"); 382 | MarkNativeAsOptional("BotMimicFix_GetLoadedRecordList"); 383 | MarkNativeAsOptional("BotMimicFix_GetFileHeaders"); 384 | MarkNativeAsOptional("BotMimicFix_GetFileCategory"); 385 | MarkNativeAsOptional("BotMimicFix_ChangeRecordName"); 386 | MarkNativeAsOptional("BotMimicFix_GetRecordBookmarks"); 387 | } 388 | #endif 389 | -------------------------------------------------------------------------------- /scripting/include/csgowiki.inc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define PREFIX "\x01[\x05CSGOWiki\x01]" 9 | #pragma dynamic 1310720 10 | 11 | #define LENGTH_VERSION 20 12 | #define LENGTH_TOKEN 40 13 | #define LENGTH_STEAMID64 20 // 17 for usuall 14 | #define LENGTH_STATUS 16 15 | #define LENGTH_NAME 33 16 | #define LENGTH_IP 27 17 | #define LENGTH_SERVER_MONITOR 2048 18 | #define LENGTH_MAPNAME 12 19 | #define LENGTH_UTILITY_FULL 13 20 | #define LENGTH_UTILITY_TINY 8 21 | #define LENGTH_UTILITY_ZH 24 22 | #define LENGTH_UTILITY_ID 12 23 | #define LENGTH_UTILITY_BRIEF 41 24 | #define LENGTH_MESSAGE 128 25 | #define DATA_DIM 3 26 | #define LENGTH_URL 256 27 | 28 | #define CSGO_ACTION_NUM 9 29 | #define CSGOWIKI_ACTION_NUM 7 30 | 31 | // 功能开关 steambind 不能关闭 32 | Handle g_hCSGOWikiEnable = INVALID_HANDLE; 33 | Handle g_hOnUtilitySubmit = INVALID_HANDLE; 34 | Handle g_hOnUtilityWiki = INVALID_HANDLE; 35 | Handle g_hWikiReqLimit = INVALID_HANDLE; 36 | Handle g_hWikiAutoKicker = INVALID_HANDLE; 37 | // wiki token 38 | Handle g_hCSGOWikiToken; 39 | // api host 40 | Handle g_hApiHost = INVALID_HANDLE; 41 | 42 | // 地图 tick信息 43 | char g_sCurrentMap[LENGTH_MAPNAME]; 44 | int g_iServerTickrate; 45 | 46 | // 插件版本信息 47 | char g_sCurrentVersion[LENGTH_VERSION]; 48 | char g_sLatestVersion[LENGTH_VERSION]; 49 | char g_sLatestInfo[LENGTH_MESSAGE]; 50 | 51 | // 道具路径 52 | const int g_iUtilityPathInterval = 2; // 间隔Frame采样 53 | int g_iPlayerUtilityPathFrameCount[MAXPLAYERS + 1]; 54 | ArrayList g_aPlayerUtilityPath[MAXPLAYERS + 1]; 55 | 56 | // --------- steam_bind.sp define ----------- 57 | enum StateBind { 58 | e_bUnknown = 0, 59 | e_bUnbind = 1, 60 | e_bBinded = 2 61 | }; 62 | 63 | StateBind g_aPlayerStateBind[MAXPLAYERS + 1]; 64 | 65 | // --------- utility_submit.sp define ----------- 66 | enum StateClient { 67 | e_cDefault = 0, 68 | e_cThrowReady = 1, 69 | e_cThrowEnd = 2, 70 | e_cAlreadyThrown = 3, 71 | e_cM_ThrowReady = 4, 72 | e_cM_ThrowEnd = 5, 73 | e_cM_AlreadyThrown = 6, 74 | e_cV_ThrowReady = 7 75 | } 76 | 77 | 78 | enum WikiAction { 79 | e_wJump = 0, 80 | e_wDuck = 1, 81 | e_wRun = 2, 82 | e_wWalk = 3, 83 | e_wStand = 4, 84 | e_wLeftclick = 5, 85 | e_wRightclick = 6 86 | } 87 | 88 | 89 | new g_aCsgoActionMap[CSGO_ACTION_NUM] = { 90 | IN_JUMP, IN_DUCK, IN_ATTACK, IN_ATTACK2, 91 | IN_MOVELEFT, IN_MOVERIGHT, IN_FORWARD, IN_BACK, IN_SPEED 92 | }; 93 | 94 | StateClient g_aPlayerStatus[MAXPLAYERS + 1]; 95 | // data for utility record 96 | GrenadeType g_aUtilityType[MAXPLAYERS + 1]; 97 | float g_aStartPositions[MAXPLAYERS + 1][DATA_DIM]; 98 | float g_aStartAngles[MAXPLAYERS + 1][DATA_DIM]; 99 | float g_aThrowPositions[MAXPLAYERS + 1][DATA_DIM]; 100 | float g_aEndspotPositions[MAXPLAYERS + 1][DATA_DIM]; 101 | float g_aUtilityVelocity[MAXPLAYERS + 1][DATA_DIM]; 102 | int g_iUtilityEntityId[MAXPLAYERS + 1]; 103 | 104 | float g_aUtilityAirtime[MAXPLAYERS + 1]; 105 | int g_aActionRecord[MAXPLAYERS + 1]; // encoded 106 | 107 | 108 | // ------------- wikipro.sp define ---------------- 109 | JSONArray g_aProMatchInfo; 110 | JSONArray g_aProMatchDetail[MAXPLAYERS + 1]; 111 | int g_aProMatchIndex[MAXPLAYERS + 1]; 112 | 113 | // ------------- utility_wiki.sp define ----------- 114 | JSONArray g_jaUtilityCollection; 115 | 116 | char g_aLastArticleId[MAXPLAYERS + 1][LENGTH_UTILITY_ID]; 117 | char g_aLastUtilityId[MAXPLAYERS + 1][LENGTH_UTILITY_ID]; 118 | 119 | JSONArray g_aUtFilterCollection[MAXPLAYERS + 1]; 120 | bool g_aReqLock[MAXPLAYERS + 1]; 121 | 122 | // ------------- utility_modify.sp define ------------ 123 | char g_aPlayerToken[MAXPLAYERS + 1][LENGTH_TOKEN]; 124 | 125 | // ------------- option.sp define ------------------ 126 | bool g_bAutoThrow[MAXPLAYERS + 1]; 127 | 128 | bool g_bBotMimicLoaded = false; --------------------------------------------------------------------------------