├── .gitignore ├── LICENSE ├── README.md ├── pawn.json ├── src ├── CMakeLists.txt ├── amx │ ├── amx.h │ ├── getch.h │ └── sclinux.h ├── amxplugin.cpp ├── cmake │ ├── .gitattributes │ ├── AMXConfig.cmake │ ├── AddSAMPPlugin.cmake │ ├── AddSAMPPluginTest.cmake │ ├── AddSAMPPluginTestPR.cmake │ ├── FindPawnCC.cmake │ ├── FindPluginRunner.cmake │ ├── FindSAMPGDK.cmake │ ├── FindSAMPSDK.cmake │ ├── FindSAMPServer.cmake │ ├── FindSAMPServerCLI.cmake │ ├── LICENSE.txt │ └── README.md ├── compilation_date.hpp ├── fmt │ ├── args.h │ ├── chrono.h │ ├── color.h │ ├── compile.h │ ├── core.h │ ├── format-inl.h │ ├── format.h │ ├── os.h │ ├── ostream.h │ ├── printf.h │ ├── ranges.h │ ├── std.h │ └── xchar.h ├── main.cpp ├── natives.hpp ├── natives_data.cpp ├── natives_global.cpp ├── natives_player.cpp ├── natives_plugin.cpp ├── plugin.h ├── plugin_version.hpp ├── plugincommon.h ├── sampgdk.cpp ├── sampgdk.hpp ├── service.cpp ├── service.hpp ├── slot_manager.cpp ├── slot_manager.hpp ├── textdraw-streamer.def ├── textdraw_data.cpp └── textdraw_data.hpp └── textdraw-streamer.inc /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [SA:MP / Open.MP] Textdraw Streamer 2 | [![GitHub Release](https://img.shields.io/github/release/nexquery/samp-textdraw-streamer.svg)](https://github.com/nexquery/samp-textdraw-streamer/releases/latest) [![Download](https://img.shields.io/github/downloads/nexquery/samp-textdraw-streamer/total?color=blue)](https://github.com/nexquery/samp-textdraw-streamer/releases/latest) [![License](https://img.shields.io/github/license/nexquery/samp-textdraw-streamer?color=blue)](https://github.com/nexquery/samp-textdraw-streamer) 3 | 4 | ## Foreword 5 | This plugin is inspired by the streamer plugin. Previously people used a lot of CreatePlayerTextDraw under OnPlayerConnect, they were reaching the limits of text drawing because they used it too much. Because they had reached the limit, they could not display the text drawings properly and were looking for a solution. I decided to make such an add-on because I was having a lot of trouble because of this problem. 6 | 7 | ## Supports 8 | The plugin now supports [open.mp](https://github.com/openmultiplayer/open.mp/releases) versions. 9 | 10 | ## Arrangements 11 | You will need to change some natives as the plugin has undergone radical changes. If you haven't used these natives before, it should work fine when you install the plugin normally. 12 | 13 | ## The Most Important Part 14 | Always add the textdraw-streamer library to the bottom of the available libraries. 15 | ```c 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | ``` 22 | 23 | ## Callbacks 24 | ```c 25 | public OnCancelDynamicTextDraw(playerid) 26 | { 27 | return 0; 28 | } 29 | 30 | public OnClickDynamicTextDraw(playerid, Text:textid) 31 | { 32 | return 0; 33 | } 34 | 35 | public OnClickDynamicPlayerTextDraw(playerid, PlayerText:textid) 36 | { 37 | return 0; 38 | } 39 | ``` 40 | 41 | ## Compilation 42 | Install gcc and g++, make and cmake. On Ubuntu you would do that like so: 43 | ``` 44 | sudo apt-get install gcc g++ make cmake 45 | ``` 46 | If you're on a 64-bit system you'll need additional packages for compiling for 32-bit: 47 | ``` 48 | sudo apt-get install gcc-multilib g++-multilib 49 | ``` 50 | Finally: 51 | ``` 52 | cd src 53 | mkdir build && cd build 54 | cmake ../ -DCMAKE_BUILD_TYPE=Release 55 | make 56 | ``` 57 | -------------------------------------------------------------------------------- /pawn.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "nexquery", 3 | "repo": "samp-textdraw-streamer", 4 | "resources": [ 5 | { 6 | "name": "^textdraw-streamer.(.*).zip$", 7 | "platform": "linux", 8 | "archive": true, 9 | "includes": ["pawno/include"], 10 | "plugins": ["plugins/textdraw-streamer.so"] 11 | }, 12 | { 13 | "name": "^textdraw-streamer.(.*).zip$", 14 | "platform": "windows", 15 | "archive": true, 16 | "includes": ["pawno/include"], 17 | "plugins": ["plugins/textdraw-streamer.dll"] 18 | } 19 | ], 20 | "runtime": { 21 | "plugins": ["nexquery/samp-textdraw-streamer"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_SUPPRESS_REGENERATION true) 2 | 3 | project(textdraw-streamer) 4 | 5 | cmake_minimum_required(VERSION 2.8) 6 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 7 | 8 | include(AMXConfig) 9 | include(AddSAMPPlugin) 10 | 11 | include_directories( 12 | ${CMAKE_CURRENT_SOURCE_DIR} 13 | ${CMAKE_CURRENT_SOURCE_DIR}/amx 14 | ${CMAKE_CURRENT_SOURCE_DIR}/fmt 15 | ) 16 | 17 | add_definitions(-DSAMPGDK_AMALGAMATION) 18 | add_definitions(-DFMT_HEADER_ONLY) 19 | 20 | add_samp_plugin(textdraw-streamer 21 | amxplugin.cpp 22 | compilation_date.hpp 23 | main.cpp 24 | natives.hpp 25 | natives_data.cpp 26 | natives_global.cpp 27 | natives_player.cpp 28 | natives_plugin.cpp 29 | plugin.h 30 | plugin_version.hpp 31 | plugincommon.h 32 | sampgdk.cpp 33 | sampgdk.hpp 34 | service.cpp 35 | service.hpp 36 | slot_manager.cpp 37 | slot_manager.hpp 38 | textdraw_data.cpp 39 | textdraw_data.hpp 40 | textdraw-streamer.def 41 | ) 42 | -------------------------------------------------------------------------------- /src/amx/amx.h: -------------------------------------------------------------------------------- 1 | /* Pawn Abstract Machine (for the Pawn language) 2 | * 3 | * Copyright (c) ITB CompuPhase, 1997-2005 4 | * 5 | * This software is provided "as-is", without any express or implied warranty. 6 | * In no event will the authors be held liable for any damages arising from 7 | * the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any purpose, 10 | * including commercial applications, and to alter it and redistribute it 11 | * freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you must not 14 | * claim that you wrote the original software. If you use this software in 15 | * a product, an acknowledgment in the product documentation would be 16 | * appreciated but is not required. 17 | * 2. Altered source versions must be plainly marked as such, and must not be 18 | * misrepresented as being the original software. 19 | * 3. This notice may not be removed or altered from any source distribution. 20 | * 21 | * Version: $Id: amx.h,v 1.5 2006/03/26 16:56:15 spookie Exp $ 22 | */ 23 | 24 | #if defined FREEBSD && !defined __FreeBSD__ 25 | #define __FreeBSD__ 26 | #endif 27 | #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ 28 | #include 29 | #endif 30 | 31 | #ifndef AMX_H_INCLUDED 32 | #define AMX_H_INCLUDED 33 | 34 | #if defined HAVE_STDINT_H 35 | #include 36 | #else 37 | #if defined __LCC__ || defined __DMC__ || defined LINUX 38 | #if defined HAVE_INTTYPES_H 39 | #include 40 | #else 41 | #include 42 | #endif 43 | #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L 44 | /* The ISO C99 defines the int16_t and int_32t types. If the compiler got 45 | * here, these types are probably undefined. 46 | */ 47 | #if defined __MACH__ 48 | #include 49 | typedef unsigned short int uint16_t; 50 | typedef unsigned long int uint32_t; 51 | #elif defined __FreeBSD__ 52 | #include 53 | #else 54 | typedef short int int16_t; 55 | typedef unsigned short int uint16_t; 56 | #if defined SN_TARGET_PS2 57 | typedef int int32_t; 58 | typedef unsigned int uint32_t; 59 | #else 60 | typedef long int int32_t; 61 | typedef unsigned long int uint32_t; 62 | #endif 63 | #if defined __WIN32__ || defined _WIN32 || defined WIN32 64 | typedef __int64 int64_t; 65 | typedef unsigned __int64 uint64_t; 66 | #define HAVE_I64 67 | #elif defined __GNUC__ 68 | typedef long long int64_t; 69 | typedef unsigned long long uint64_t; 70 | #define HAVE_I64 71 | #endif 72 | #endif 73 | #endif 74 | #define HAVE_STDINT_H 75 | #endif 76 | #if defined _LP64 || defined WIN64 || defined _WIN64 77 | #if !defined __64BIT__ 78 | #define __64BIT__ 79 | #endif 80 | #endif 81 | 82 | #if HAVE_ALLOCA_H 83 | #include 84 | #endif 85 | #if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */ 86 | #if !defined alloca 87 | #define alloca(n) _alloca(n) 88 | #endif 89 | #endif 90 | 91 | #if !defined arraysize 92 | #define arraysize(array) (sizeof(array) / sizeof((array)[0])) 93 | #endif 94 | 95 | #ifdef __cplusplus 96 | extern "C" { 97 | #endif 98 | 99 | #if defined PAWN_DLL 100 | #if !defined AMX_NATIVE_CALL 101 | #define AMX_NATIVE_CALL __stdcall 102 | #endif 103 | #if !defined AMXAPI 104 | #define AMXAPI __stdcall 105 | #endif 106 | #endif 107 | 108 | /* calling convention for native functions */ 109 | #if !defined AMX_NATIVE_CALL 110 | #define AMX_NATIVE_CALL 111 | #endif 112 | /* calling convention for all interface functions and callback functions */ 113 | #if !defined AMXAPI 114 | #if defined STDECL 115 | #define AMXAPI __stdcall 116 | #elif defined CDECL 117 | #define AMXAPI __cdecl 118 | #elif defined GCC_HASCLASSVISIBILITY 119 | #define AMXAPI __attribute__ ((visibility("default"))) 120 | #else 121 | #define AMXAPI 122 | #endif 123 | #endif 124 | #if !defined AMXEXPORT 125 | #define AMXEXPORT 126 | #endif 127 | 128 | /* File format version Required AMX version 129 | * 0 (original version) 0 130 | * 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1 131 | * 2 (compressed files) 2 132 | * 3 (public variables) 2 133 | * 4 (opcodes SWAP.pri/alt and PUSHADDR) 4 134 | * 5 (tagnames table) 4 135 | * 6 (reformatted header) 6 136 | * 7 (name table, opcodes SYMTAG & SYSREQ.D) 7 137 | * 8 (opcode STMT, renewed debug interface) 8 138 | */ 139 | #define CUR_FILE_VERSION 8 /* current file version; also the current AMX version */ 140 | #define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */ 141 | #define MIN_AMX_VERSION 8 /* minimum AMX version needed to support the current file format */ 142 | 143 | #if !defined PAWN_CELL_SIZE 144 | #define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */ 145 | #endif 146 | #if PAWN_CELL_SIZE==16 147 | typedef uint16_t ucell; 148 | typedef int16_t cell; 149 | #elif PAWN_CELL_SIZE==32 150 | typedef uint32_t ucell; 151 | typedef int32_t cell; 152 | #elif PAWN_CELL_SIZE==64 153 | typedef uint64_t ucell; 154 | typedef int64_t cell; 155 | #else 156 | #error Unsupported cell size (PAWN_CELL_SIZE) 157 | #endif 158 | 159 | #define UNPACKEDMAX ((1L << (sizeof(cell)-1)*8) - 1) 160 | #define UNLIMITED (~1u >> 1) 161 | 162 | struct tagAMX; 163 | typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params); 164 | typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index, 165 | cell *result, cell *params); 166 | typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx); 167 | #if !defined _FAR 168 | #define _FAR 169 | #endif 170 | 171 | #if defined _MSC_VER 172 | #pragma warning(disable:4103) /* disable warning message 4103 that complains 173 | * about pragma pack in a header file */ 174 | #pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */ 175 | #endif 176 | 177 | /* Some compilers do not support the #pragma align, which should be fine. Some 178 | * compilers give a warning on unknown #pragmas, which is not so fine... 179 | */ 180 | #if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN 181 | #define AMX_NO_ALIGN 182 | #endif 183 | 184 | #if defined __GNUC__ 185 | #define PACKED __attribute__((packed)) 186 | #else 187 | #define PACKED 188 | #endif 189 | 190 | #if !defined AMX_NO_ALIGN 191 | #if defined LINUX || defined __FreeBSD__ 192 | #pragma pack(1) /* structures must be packed (byte-aligned) */ 193 | #elif defined MACOS && defined __MWERKS__ 194 | #pragma options align=mac68k 195 | #else 196 | #pragma pack(push) 197 | #pragma pack(1) /* structures must be packed (byte-aligned) */ 198 | #if defined __TURBOC__ 199 | #pragma option -a- /* "pack" pragma for older Borland compilers */ 200 | #endif 201 | #endif 202 | #endif 203 | 204 | typedef struct tagAMX_NATIVE_INFO { 205 | const char _FAR *name PACKED; 206 | AMX_NATIVE func PACKED; 207 | } PACKED AMX_NATIVE_INFO; 208 | 209 | #define AMX_USERNUM 4 210 | #define sEXPMAX 19 /* maximum name length for file version <= 6 */ 211 | #define sNAMEMAX 31 /* maximum name length of symbol name */ 212 | 213 | typedef struct tagAMX_FUNCSTUB { 214 | ucell address PACKED; 215 | char name[sEXPMAX+1] PACKED; 216 | } PACKED AMX_FUNCSTUB; 217 | 218 | typedef struct tagFUNCSTUBNT { 219 | ucell address PACKED; 220 | uint32_t nameofs PACKED; 221 | } PACKED AMX_FUNCSTUBNT; 222 | 223 | /* The AMX structure is the internal structure for many functions. Not all 224 | * fields are valid at all times; many fields are cached in local variables. 225 | */ 226 | typedef struct tagAMX { 227 | unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */ 228 | unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */ 229 | AMX_CALLBACK callback PACKED; 230 | AMX_DEBUG debug PACKED; /* debug callback */ 231 | /* for external functions a few registers must be accessible from the outside */ 232 | cell cip PACKED; /* instruction pointer: relative to base + amxhdr->cod */ 233 | cell frm PACKED; /* stack frame base: relative to base + amxhdr->dat */ 234 | cell hea PACKED; /* top of the heap: relative to base + amxhdr->dat */ 235 | cell hlw PACKED; /* bottom of the heap: relative to base + amxhdr->dat */ 236 | cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */ 237 | cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */ 238 | int flags PACKED; /* current status, see amx_Flags() */ 239 | /* user data */ 240 | long usertags[AMX_USERNUM] PACKED; 241 | void _FAR *userdata[AMX_USERNUM] PACKED; 242 | /* native functions can raise an error */ 243 | int error PACKED; 244 | /* passing parameters requires a "count" field */ 245 | int paramcount; 246 | /* the sleep opcode needs to store the full AMX status */ 247 | cell pri PACKED; 248 | cell alt PACKED; 249 | cell reset_stk PACKED; 250 | cell reset_hea PACKED; 251 | cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */ 252 | #if defined JIT 253 | /* support variables for the JIT */ 254 | int reloc_size PACKED; /* required temporary buffer for relocations */ 255 | long code_size PACKED; /* estimated memory footprint of the native code */ 256 | #endif 257 | } PACKED AMX; 258 | 259 | /* The AMX_HEADER structure is both the memory format as the file format. The 260 | * structure is used internaly. 261 | */ 262 | typedef struct tagAMX_HEADER { 263 | int32_t size PACKED; /* size of the "file" */ 264 | uint16_t magic PACKED; /* signature */ 265 | char file_version PACKED; /* file format version */ 266 | char amx_version PACKED; /* required version of the AMX */ 267 | int16_t flags PACKED; 268 | int16_t defsize PACKED; /* size of a definition record */ 269 | int32_t cod PACKED; /* initial value of COD - code block */ 270 | int32_t dat PACKED; /* initial value of DAT - data block */ 271 | int32_t hea PACKED; /* initial value of HEA - start of the heap */ 272 | int32_t stp PACKED; /* initial value of STP - stack top */ 273 | int32_t cip PACKED; /* initial value of CIP - the instruction pointer */ 274 | int32_t publics PACKED; /* offset to the "public functions" table */ 275 | int32_t natives PACKED; /* offset to the "native functions" table */ 276 | int32_t libraries PACKED; /* offset to the table of libraries */ 277 | int32_t pubvars PACKED; /* the "public variables" table */ 278 | int32_t tags PACKED; /* the "public tagnames" table */ 279 | int32_t nametable PACKED; /* name table */ 280 | } PACKED AMX_HEADER; 281 | 282 | #if PAWN_CELL_SIZE==16 283 | #define AMX_MAGIC 0xf1e2 284 | #elif PAWN_CELL_SIZE==32 285 | #define AMX_MAGIC 0xf1e0 286 | #elif PAWN_CELL_SIZE==64 287 | #define AMX_MAGIC 0xf1e1 288 | #endif 289 | 290 | enum { 291 | AMX_ERR_NONE, 292 | /* reserve the first 15 error codes for exit codes of the abstract machine */ 293 | AMX_ERR_EXIT, /* forced exit */ 294 | AMX_ERR_ASSERT, /* assertion failed */ 295 | AMX_ERR_STACKERR, /* stack/heap collision */ 296 | AMX_ERR_BOUNDS, /* index out of bounds */ 297 | AMX_ERR_MEMACCESS, /* invalid memory access */ 298 | AMX_ERR_INVINSTR, /* invalid instruction */ 299 | AMX_ERR_STACKLOW, /* stack underflow */ 300 | AMX_ERR_HEAPLOW, /* heap underflow */ 301 | AMX_ERR_CALLBACK, /* no callback, or invalid callback */ 302 | AMX_ERR_NATIVE, /* native function failed */ 303 | AMX_ERR_DIVIDE, /* divide by zero */ 304 | AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */ 305 | AMX_ERR_INVSTATE, /* invalid state for this access */ 306 | 307 | AMX_ERR_MEMORY = 16, /* out of memory */ 308 | AMX_ERR_FORMAT, /* invalid file format */ 309 | AMX_ERR_VERSION, /* file is for a newer version of the AMX */ 310 | AMX_ERR_NOTFOUND, /* function not found */ 311 | AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */ 312 | AMX_ERR_DEBUG, /* debugger cannot run */ 313 | AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */ 314 | AMX_ERR_USERDATA, /* unable to set user data field (table full) */ 315 | AMX_ERR_INIT_JIT, /* cannot initialize the JIT */ 316 | AMX_ERR_PARAMS, /* parameter error */ 317 | AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */ 318 | AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */ 319 | }; 320 | 321 | /* AMX_FLAG_CHAR16 0x01 no longer used */ 322 | #define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */ 323 | #define AMX_FLAG_COMPACT 0x04 /* compact encoding */ 324 | #define AMX_FLAG_BYTEOPC 0x08 /* opcode is a byte (not a cell) */ 325 | #define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no STMT opcode */ 326 | #define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */ 327 | #define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */ 328 | #define AMX_FLAG_BROWSE 0x4000 /* busy browsing */ 329 | #define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */ 330 | 331 | #define AMX_EXEC_MAIN -1 /* start at program entry point */ 332 | #define AMX_EXEC_CONT -2 /* continue from last address */ 333 | 334 | #define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24)) 335 | 336 | #if !defined AMX_COMPACTMARGIN 337 | #define AMX_COMPACTMARGIN 64 338 | #endif 339 | 340 | /* for native functions that use floating point parameters, the following 341 | * two macros are convenient for casting a "cell" into a "float" type _without_ 342 | * changing the bit pattern 343 | */ 344 | #if PAWN_CELL_SIZE==32 345 | #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ 346 | #define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */ 347 | #elif PAWN_CELL_SIZE==64 348 | #define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */ 349 | #define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */ 350 | #else 351 | #error Unsupported cell size 352 | #endif 353 | 354 | #define amx_StrParam(amx,param,result) \ 355 | do { \ 356 | cell *amx_cstr_; int amx_length_; \ 357 | amx_GetAddr((amx), (param), &amx_cstr_); \ 358 | amx_StrLen(amx_cstr_, &amx_length_); \ 359 | if (amx_length_ > 0 && \ 360 | ((result) = (char*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \ 361 | amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_ + 1); \ 362 | else (result) = NULL; \ 363 | } while (0) 364 | 365 | uint16_t * AMXAPI amx_Align16(uint16_t *v); 366 | uint32_t * AMXAPI amx_Align32(uint32_t *v); 367 | #if defined _I64_MAX || defined HAVE_I64 368 | uint64_t * AMXAPI amx_Align64(uint64_t *v); 369 | #endif 370 | int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); 371 | int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params); 372 | int AMXAPI amx_Cleanup(AMX *amx); 373 | int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data); 374 | int AMXAPI amx_Exec(AMX *amx, cell *retval, int index); 375 | int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index); 376 | int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index); 377 | int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr); 378 | int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname); 379 | int AMXAPI amx_Flags(AMX *amx,uint16_t *flags); 380 | int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr); 381 | int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname); 382 | int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname); 383 | int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr); 384 | int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size); 385 | int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id); 386 | int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr); 387 | int AMXAPI amx_Init(AMX *amx, void *program); 388 | int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code); 389 | int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap); 390 | int AMXAPI amx_NameLength(AMX *amx, int *length); 391 | AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func); 392 | int AMXAPI amx_NumNatives(AMX *amx, int *number); 393 | int AMXAPI amx_NumPublics(AMX *amx, int *number); 394 | int AMXAPI amx_NumPubVars(AMX *amx, int *number); 395 | int AMXAPI amx_NumTags(AMX *amx, int *number); 396 | int AMXAPI amx_Push(AMX *amx, cell value); 397 | int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells); 398 | int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar); 399 | int AMXAPI amx_RaiseError(AMX *amx, int error); 400 | int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); 401 | int AMXAPI amx_Release(AMX *amx, cell amx_addr); 402 | int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback); 403 | int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug); 404 | int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size); 405 | int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr); 406 | int AMXAPI amx_StrLen(const cell *cstring, int *length); 407 | int AMXAPI amx_UTF8Check(const char *string, int *length); 408 | int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value); 409 | int AMXAPI amx_UTF8Len(const cell *cstr, int *length); 410 | int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value); 411 | 412 | #if PAWN_CELL_SIZE==16 413 | #define amx_AlignCell(v) amx_Align16(v) 414 | #elif PAWN_CELL_SIZE==32 415 | #define amx_AlignCell(v) amx_Align32(v) 416 | #elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64) 417 | #define amx_AlignCell(v) amx_Align64(v) 418 | #else 419 | #error Unsupported cell size 420 | #endif 421 | 422 | #define amx_RegisterFunc(amx, name, func) \ 423 | amx_Register((amx), amx_NativeInfo((name),(func)), 1); 424 | 425 | #if !defined AMX_NO_ALIGN 426 | #if defined LINUX || defined __FreeBSD__ 427 | #pragma pack() /* reset default packing */ 428 | #elif defined MACOS && defined __MWERKS__ 429 | #pragma options align=reset 430 | #else 431 | #pragma pack(pop) /* reset previous packing */ 432 | #endif 433 | #endif 434 | 435 | #ifdef __cplusplus 436 | } 437 | #endif 438 | 439 | #endif /* AMX_H_INCLUDED */ 440 | -------------------------------------------------------------------------------- /src/amx/getch.h: -------------------------------------------------------------------------------- 1 | /* Extremely inefficient but portable POSIX getch(), see getch.c */ 2 | #ifndef GETCH_H 3 | #define GETCH_H 4 | 5 | #if defined __cplusplus 6 | extern "C" { 7 | #endif 8 | int getch(void); 9 | int kbhit(void); 10 | 11 | #if defined __cplusplus 12 | } 13 | #endif 14 | 15 | #endif /* GETCH_H */ 16 | -------------------------------------------------------------------------------- /src/amx/sclinux.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Things needed to compile under linux. 3 | * 4 | * Should be reworked totally to use GNU's 'configure' 5 | */ 6 | #ifndef SCLINUX_H 7 | #define SCLINUX_H 8 | 9 | /* getchar() is not a 'cool' replacement for MSDOS getch: Linux/unix depends on the features activated or not about the 10 | * controlling terminal's tty. This means that ioctl(2) calls must be performed, for instance to have the controlling 11 | * terminal tty's in 'raw' mode, if we want to be able to fetch a single character. This also means that everything must 12 | * be put back correctly when the function ends. See GETCH.C for an implementation. 13 | * 14 | * For interactive use of SRUN/SDBG if would be much better to use GNU's readline package: the user would be able to 15 | * have a complete emacs/vi like line editing system. 16 | */ 17 | #include "getch.h" 18 | 19 | #define stricmp(a,b) strcasecmp(a,b) 20 | #define strnicmp(a,b,c) strncasecmp(a,b,c) 21 | 22 | /* 23 | * WinWorld wants '\'. Unices do not. 24 | */ 25 | #define DIRECTORY_SEP_CHAR '/' 26 | #define DIRECTORY_SEP_STR "/" 27 | 28 | /* 29 | * SC assumes that a computer is Little Endian unless told otherwise. It uses 30 | * (and defines) the macros BYTE_ORDER and BIG_ENDIAN. 31 | * For Linux, we must overrule these settings with those defined in glibc. 32 | */ 33 | #if !defined __BYTE_ORDER 34 | # include 35 | #endif 36 | 37 | #if defined __OpenBSD__ || defined __FreeBSD__ 38 | # define __BYTE_ORDER BYTE_ORDER 39 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 40 | # define __BIG_ENDIAN BIG_ENDIAN 41 | #endif 42 | 43 | #if !defined __BYTE_ORDER 44 | # error "Can't figure computer byte order (__BYTE_ORDER macro not found)" 45 | #endif 46 | 47 | #endif /* SCLINUX_H */ 48 | -------------------------------------------------------------------------------- /src/amxplugin.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------- 2 | // 3 | // SA-MP Multiplayer Modification For GTA:SA 4 | // Copyright 2004-2009 SA-MP Team 5 | // 6 | //---------------------------------------------------------- 7 | // 8 | // This provides an interface to call amx library functions 9 | // within samp-server. 10 | // 11 | //---------------------------------------------------------- 12 | 13 | #include "plugin.h" 14 | 15 | //---------------------------------------------------------- 16 | 17 | void *pAMXFunctions; 18 | 19 | //---------------------------------------------------------- 20 | 21 | typedef uint16_t * AMXAPI (*amx_Align16_t)(uint16_t *v); 22 | uint16_t * AMXAPI amx_Align16(uint16_t *v) 23 | { 24 | amx_Align16_t fn = ((amx_Align16_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align16]; 25 | return fn(v); 26 | } 27 | 28 | typedef uint32_t * AMXAPI (*amx_Align32_t)(uint32_t *v); 29 | uint32_t * AMXAPI amx_Align32(uint32_t *v) 30 | { 31 | amx_Align32_t fn = ((amx_Align32_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align32]; 32 | return fn(v); 33 | } 34 | 35 | #if defined _I64_MAX || defined HAVE_I64 36 | typedef uint64_t * AMXAPI (*amx_Align64_t)(uint64_t *v); 37 | uint64_t * AMXAPI amx_Align64(uint64_t *v) 38 | { 39 | amx_Align64_t fn = ((amx_Align64_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align64]; 40 | return fn(v); 41 | } 42 | 43 | #endif 44 | typedef int AMXAPI (*amx_Allot_t)(AMX *amx, int cells, cell *amx_addr, cell **phys_addr); 45 | int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr) 46 | { 47 | amx_Allot_t fn = ((amx_Allot_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Allot]; 48 | return fn(amx, cells, amx_addr, phys_addr); 49 | } 50 | 51 | typedef int AMXAPI (*amx_Callback_t)(AMX *amx, cell index, cell *result, cell *params); 52 | int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params) 53 | { 54 | amx_Callback_t fn = ((amx_Callback_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Callback]; 55 | return fn(amx, index, result, params); 56 | } 57 | 58 | typedef int AMXAPI (*amx_Cleanup_t)(AMX *amx); 59 | int AMXAPI amx_Cleanup(AMX *amx) 60 | { 61 | amx_Cleanup_t fn = ((amx_Cleanup_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Cleanup]; 62 | return fn(amx); 63 | } 64 | 65 | typedef int AMXAPI (*amx_Clone_t)(AMX *amxClone, AMX *amxSource, void *data); 66 | int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data) 67 | { 68 | amx_Clone_t fn = ((amx_Clone_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Clone]; 69 | return fn(amxClone, amxSource, data); 70 | } 71 | 72 | typedef int AMXAPI (*amx_Exec_t)(AMX *amx, cell *retval, int index); 73 | int AMXAPI amx_Exec(AMX *amx, cell *retval, int index) 74 | { 75 | amx_Exec_t fn = ((amx_Exec_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]; 76 | return fn(amx, retval, index); 77 | } 78 | 79 | typedef int AMXAPI (*amx_FindNative_t)(AMX *amx, const char *name, int *index); 80 | int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index) 81 | { 82 | amx_FindNative_t fn = ((amx_FindNative_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_FindNative]; 83 | return fn(amx, name, index); 84 | } 85 | 86 | typedef int AMXAPI (*amx_FindPublic_t)(AMX *amx, const char *funcname, int *index); 87 | int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index) 88 | { 89 | amx_FindPublic_t fn = ((amx_FindPublic_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_FindPublic]; 90 | return fn(amx, funcname, index); 91 | } 92 | 93 | typedef int AMXAPI (*amx_FindPubVar_t)(AMX *amx, const char *varname, cell *amx_addr); 94 | int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr) 95 | { 96 | amx_FindPubVar_t fn = ((amx_FindPubVar_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_FindPubVar]; 97 | return fn(amx, varname, amx_addr); 98 | } 99 | 100 | typedef int AMXAPI (*amx_FindTagId_t)(AMX *amx, cell tag_id, char *tagname); 101 | int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname) 102 | { 103 | amx_FindTagId_t fn = ((amx_FindTagId_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_FindTagId]; 104 | return fn(amx, tag_id, tagname); 105 | } 106 | 107 | typedef int AMXAPI (*amx_Flags_t)(AMX *amx,uint16_t *flags); 108 | int AMXAPI amx_Flags(AMX *amx,uint16_t *flags) 109 | { 110 | amx_Flags_t fn = ((amx_Flags_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Flags]; 111 | return fn(amx,flags); 112 | } 113 | 114 | typedef int AMXAPI (*amx_GetAddr_t)(AMX *amx,cell amx_addr,cell **phys_addr); 115 | int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr) 116 | { 117 | amx_GetAddr_t fn = ((amx_GetAddr_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetAddr]; 118 | return fn(amx,amx_addr,phys_addr); 119 | } 120 | 121 | typedef int AMXAPI (*amx_GetNative_t)(AMX *amx, int index, char *funcname); 122 | int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname) 123 | { 124 | amx_GetNative_t fn = ((amx_GetNative_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetNative]; 125 | return fn(amx, index, funcname); 126 | } 127 | 128 | typedef int AMXAPI (*amx_GetPublic_t)(AMX *amx, int index, char *funcname); 129 | int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname) 130 | { 131 | amx_GetPublic_t fn = ((amx_GetPublic_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetPublic]; 132 | return fn(amx, index, funcname); 133 | } 134 | 135 | typedef int AMXAPI (*amx_GetPubVar_t)(AMX *amx, int index, char *varname, cell *amx_addr); 136 | int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr) 137 | { 138 | amx_GetPubVar_t fn = ((amx_GetPubVar_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetPubVar]; 139 | return fn(amx, index, varname, amx_addr); 140 | } 141 | 142 | typedef int AMXAPI (*amx_GetString_t)(char *dest,const cell *source, int use_wchar, size_t size); 143 | int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size) 144 | { 145 | amx_GetString_t fn = ((amx_GetString_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetString]; 146 | return fn(dest,source, use_wchar, size); 147 | } 148 | 149 | typedef int AMXAPI (*amx_GetTag_t)(AMX *amx, int index, char *tagname, cell *tag_id); 150 | int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id) 151 | { 152 | amx_GetTag_t fn = ((amx_GetTag_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetTag]; 153 | return fn(amx, index, tagname, tag_id); 154 | } 155 | 156 | typedef int AMXAPI (*amx_GetUserData_t)(AMX *amx, long tag, void **ptr); 157 | int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr) 158 | { 159 | amx_GetUserData_t fn = ((amx_GetUserData_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_GetUserData]; 160 | return fn(amx, tag, ptr); 161 | } 162 | 163 | typedef int AMXAPI (*amx_Init_t)(AMX *amx, void *program); 164 | int AMXAPI amx_Init(AMX *amx, void *program) 165 | { 166 | amx_Init_t fn = ((amx_Init_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Init]; 167 | return fn(amx, program); 168 | } 169 | 170 | typedef int AMXAPI (*amx_InitJIT_t)(AMX *amx, void *reloc_table, void *native_code); 171 | int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code) 172 | { 173 | amx_InitJIT_t fn = ((amx_InitJIT_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_InitJIT]; 174 | return fn(amx, reloc_table, native_code); 175 | } 176 | 177 | typedef int AMXAPI (*amx_MemInfo_t)(AMX *amx, long *codesize, long *datasize, long *stackheap); 178 | int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap) 179 | { 180 | amx_MemInfo_t fn = ((amx_MemInfo_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_MemInfo]; 181 | return fn(amx, codesize, datasize, stackheap); 182 | } 183 | 184 | typedef int AMXAPI (*amx_NameLength_t)(AMX *amx, int *length); 185 | int AMXAPI amx_NameLength(AMX *amx, int *length) 186 | { 187 | amx_NameLength_t fn = ((amx_NameLength_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NameLength]; 188 | return fn(amx, length); 189 | } 190 | 191 | typedef AMX_NATIVE_INFO * AMXAPI (*amx_NativeInfo_t)(const char *name, AMX_NATIVE func); 192 | AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func) 193 | { 194 | amx_NativeInfo_t fn = ((amx_NativeInfo_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NativeInfo]; 195 | return fn(name, func); 196 | } 197 | 198 | typedef int AMXAPI (*amx_NumNatives_t)(AMX *amx, int *number); 199 | int AMXAPI amx_NumNatives(AMX *amx, int *number) 200 | { 201 | amx_NumNatives_t fn = ((amx_NumNatives_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NumNatives]; 202 | return fn(amx, number); 203 | } 204 | 205 | typedef int AMXAPI (*amx_NumPublics_t)(AMX *amx, int *number); 206 | int AMXAPI amx_NumPublics(AMX *amx, int *number) 207 | { 208 | amx_NumPublics_t fn = ((amx_NumPublics_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NumPublics]; 209 | return fn(amx, number); 210 | } 211 | 212 | typedef int AMXAPI (*amx_NumPubVars_t)(AMX *amx, int *number); 213 | int AMXAPI amx_NumPubVars(AMX *amx, int *number) 214 | { 215 | amx_NumPubVars_t fn = ((amx_NumPubVars_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NumPubVars]; 216 | return fn(amx, number); 217 | } 218 | 219 | typedef int AMXAPI (*amx_NumTags_t)(AMX *amx, int *number); 220 | int AMXAPI amx_NumTags(AMX *amx, int *number) 221 | { 222 | amx_NumTags_t fn = ((amx_NumTags_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_NumTags]; 223 | return fn(amx, number); 224 | } 225 | 226 | typedef int AMXAPI (*amx_Push_t)(AMX *amx, cell value); 227 | int AMXAPI amx_Push(AMX *amx, cell value) 228 | { 229 | amx_Push_t fn = ((amx_Push_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Push]; 230 | return fn(amx, value); 231 | } 232 | 233 | typedef int AMXAPI (*amx_PushArray_t)(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells); 234 | int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells) 235 | { 236 | amx_PushArray_t fn = ((amx_PushArray_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_PushArray]; 237 | return fn(amx, amx_addr, phys_addr, array, numcells); 238 | } 239 | 240 | typedef int AMXAPI (*amx_PushString_t)(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar); 241 | int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar) 242 | { 243 | amx_PushString_t fn = ((amx_PushString_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_PushString]; 244 | return fn(amx, amx_addr, phys_addr, string, pack, use_wchar); 245 | } 246 | 247 | typedef int AMXAPI (*amx_RaiseError_t)(AMX *amx, int error); 248 | int AMXAPI amx_RaiseError(AMX *amx, int error) 249 | { 250 | amx_RaiseError_t fn = ((amx_RaiseError_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_RaiseError]; 251 | return fn(amx, error); 252 | } 253 | 254 | typedef int AMXAPI (*amx_Register_t)(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number); 255 | int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number) 256 | { 257 | amx_Register_t fn = ((amx_Register_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Register]; 258 | return fn(amx, nativelist, number); 259 | } 260 | 261 | typedef int AMXAPI (*amx_Release_t)(AMX *amx, cell amx_addr); 262 | int AMXAPI amx_Release(AMX *amx, cell amx_addr) 263 | { 264 | amx_Release_t fn = ((amx_Release_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_Release]; 265 | return fn(amx, amx_addr); 266 | } 267 | 268 | typedef int AMXAPI (*amx_SetCallback_t)(AMX *amx, AMX_CALLBACK callback); 269 | int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback) 270 | { 271 | amx_SetCallback_t fn = ((amx_SetCallback_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_SetCallback]; 272 | return fn(amx, callback); 273 | } 274 | 275 | typedef int AMXAPI (*amx_SetDebugHook_t)(AMX *amx, AMX_DEBUG debug); 276 | int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug) 277 | { 278 | amx_SetDebugHook_t fn = ((amx_SetDebugHook_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_SetDebugHook]; 279 | return fn(amx, debug); 280 | } 281 | 282 | typedef int AMXAPI (*amx_SetString_t)(cell *dest, const char *source, int pack, int use_wchar, size_t size); 283 | int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size) 284 | { 285 | amx_SetString_t fn = ((amx_SetString_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_SetString]; 286 | return fn(dest, source, pack, use_wchar, size); 287 | } 288 | 289 | typedef int AMXAPI (*amx_SetUserData_t)(AMX *amx, long tag, void *ptr); 290 | int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr) 291 | { 292 | amx_SetUserData_t fn = ((amx_SetUserData_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_SetUserData]; 293 | return fn(amx, tag, ptr); 294 | } 295 | 296 | typedef int AMXAPI (*amx_StrLen_t)(const cell *cstring, int *length); 297 | int AMXAPI amx_StrLen(const cell *cstring, int *length) 298 | { 299 | amx_StrLen_t fn = ((amx_StrLen_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_StrLen]; 300 | return fn(cstring, length); 301 | } 302 | 303 | typedef int AMXAPI (*amx_UTF8Check_t)(const char *string, int *length); 304 | int AMXAPI amx_UTF8Check(const char *string, int *length) 305 | { 306 | amx_UTF8Check_t fn = ((amx_UTF8Check_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_UTF8Check]; 307 | return fn(string, length); 308 | } 309 | 310 | typedef int AMXAPI (*amx_UTF8Get_t)(const char *string, const char **endptr, cell *value); 311 | int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value) 312 | { 313 | amx_UTF8Get_t fn = ((amx_UTF8Get_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_UTF8Get]; 314 | return fn(string, endptr, value); 315 | } 316 | 317 | typedef int AMXAPI (*amx_UTF8Len_t)(const cell *cstr, int *length); 318 | int AMXAPI amx_UTF8Len(const cell *cstr, int *length) 319 | { 320 | amx_UTF8Len_t fn = ((amx_UTF8Len_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_UTF8Len]; 321 | return fn(cstr, length); 322 | } 323 | 324 | typedef int AMXAPI (*amx_UTF8Put_t)(char *string, char **endptr, int maxchars, cell value); 325 | int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value) 326 | { 327 | amx_UTF8Put_t fn = ((amx_UTF8Put_t*)pAMXFunctions)[PLUGIN_AMX_EXPORT_UTF8Put]; 328 | return fn(string, endptr, maxchars, value); 329 | } 330 | 331 | //---------------------------------------------------------- 332 | // EOF 333 | -------------------------------------------------------------------------------- /src/cmake/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /src/cmake/AMXConfig.cmake: -------------------------------------------------------------------------------- 1 | include(CheckIncludeFile) 2 | 3 | check_include_file(alloca.h HAVE_ALLOCA_H) 4 | if(HAVE_ALLOCA_H) 5 | add_definitions(-DHAVE_ALLOCA_H) 6 | endif() 7 | check_include_file(inttypes.h HAVE_INTTYPES_H) 8 | if(HAVE_INTTYPES_H) 9 | add_definitions(-DHAVE_INTTYPES_H) 10 | endif() 11 | check_include_file(malloc.h HAVE_MALLOC_H) 12 | if(HAVE_MALLOC_H) 13 | add_definitions(-DHAVE_MALLOC_H) 14 | endif() 15 | check_include_file(stdint.h HAVE_STDINT_H) 16 | if(HAVE_STDINT_H) 17 | add_definitions(-DHAVE_STDINT_H) 18 | endif() 19 | -------------------------------------------------------------------------------- /src/cmake/AddSAMPPlugin.cmake: -------------------------------------------------------------------------------- 1 | function(add_samp_plugin name) 2 | add_library(${name} MODULE ${ARGN}) 3 | 4 | set_target_properties(${name} PROPERTIES PREFIX "") 5 | 6 | if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 7 | set_property(TARGET ${name} APPEND_STRING PROPERTY COMPILE_FLAGS " -m32") 8 | set_property(TARGET ${name} APPEND_STRING PROPERTY LINK_FLAGS " -m32") 9 | endif() 10 | 11 | if(CMAKE_COMPILER_IS_GNUCXX) 12 | set_property(TARGET ${name} APPEND_STRING PROPERTY 13 | COMPILE_FLAGS " -Wno-attributes") 14 | endif() 15 | 16 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 17 | set_property(TARGET ${name} APPEND_STRING PROPERTY 18 | COMPILE_FLAGS " -Wno-ignored-attributes") 19 | endif() 20 | 21 | if(WIN32 AND CMAKE_COMPILER_IS_GNUCC) 22 | set_property(TARGET ${name} APPEND_STRING PROPERTY 23 | LINK_FLAGS " -Wl,--enable-stdcall-fixup") 24 | endif() 25 | 26 | if(CYGWIN) 27 | set_property(TARGET ${name} APPEND PROPERTY COMPILE_DEFINITIONS "WIN32") 28 | set_property(TARGET ${name} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--kill-at") 29 | elseif(UNIX AND NOT WIN32 AND NOT APPLE) 30 | set_property(TARGET ${name} APPEND PROPERTY COMPILE_DEFINITIONS "LINUX") 31 | endif() 32 | 33 | if(MINGW) 34 | # Work around missing #include in /amx/amx.h. 35 | set_property(TARGET ${name} APPEND_STRING PROPERTY COMPILE_FLAGS " -include stddef.h") 36 | endif() 37 | endfunction() 38 | -------------------------------------------------------------------------------- /src/cmake/AddSAMPPluginTest.cmake: -------------------------------------------------------------------------------- 1 | # AddSAMPPluginTest - add tests for SA-MP plugins. 2 | # 3 | # This module reuires the samp-server-cli script to be present in PATH in 4 | # order to be able to run the tests. The script can be downloaded here: 5 | # 6 | # https://github.com/Zeex/samp-server-cli 7 | # 8 | # Additionally the SAMP_SERVER_ROOT environment variable must be defined and 9 | # must point to the SA-MP server's root directory. 10 | 11 | include(CMakeParseArguments) 12 | 13 | function(add_samp_plugin_test) 14 | set(name "${ARGV0}") 15 | 16 | set(options TARGET OUTPUT_FILE SCRIPT TIMEOUT CONFIG WORKING_DIRECTORY) 17 | cmake_parse_arguments(ARG "" "${options}" "" ${ARGN}) 18 | 19 | find_package(SAMPServerCLI REQUIRED) 20 | set(command ${SAMPServerCLI_EXECUTABLE}) 21 | 22 | if(ARG_SCRIPT) 23 | list(APPEND args --gamemode ${ARG_SCRIPT}) 24 | endif() 25 | 26 | if(ARG_TIMEOUT) 27 | list(APPEND args --timeout ${ARG_TIMEOUT}) 28 | endif() 29 | 30 | if(ARG_WORKING_DIRECTORY) 31 | list(APPEND args --workdir ${ARG_WORKING_DIRECTORY}) 32 | endif() 33 | 34 | add_test(NAME ${name} COMMAND ${command} ${args} --output 35 | --plugin $) 36 | 37 | if(ARG_SCRIPT) 38 | get_filename_component(AMX_PATH ${ARG_SCRIPT} DIRECTORY) 39 | set_tests_properties(${name} PROPERTIES ENVIRONMENT AMX_PATH=${AMX_PATH}) 40 | endif() 41 | 42 | if(ARG_OUTPUT_FILE) 43 | file(READ ${ARG_OUTPUT_FILE} output) 44 | set_tests_properties(${name} PROPERTIES PASS_REGULAR_EXPRESSION ${output}) 45 | endif() 46 | endfunction() 47 | -------------------------------------------------------------------------------- /src/cmake/AddSAMPPluginTestPR.cmake: -------------------------------------------------------------------------------- 1 | # AddSAMPPluginTestPR - add tests for SA-MP plugins using plugin-runner. 2 | # 3 | # To use this module you will also need to have FindPluginRunner in your CMake 4 | # module path. 5 | 6 | include(CMakeParseArguments) 7 | 8 | function(add_samp_plugin_test) 9 | set(name "${ARGV0}") 10 | 11 | cmake_parse_arguments( 12 | ARG 13 | "" 14 | "OUTPUT_FILE;SCRIPT;TIMEOUT;CONFIG;WORKING_DIRECTORY" 15 | "TARGETS" 16 | ${ARGN} 17 | ) 18 | 19 | find_package(PluginRunner REQUIRED) 20 | set(command ${PluginRunner_EXECUTABLE}) 21 | 22 | if(NOT ARG_SCRIPT) 23 | message(FATAL_ERROR "SCRIPT argument is required") 24 | endif() 25 | 26 | set(plugins "") 27 | foreach(target ${ARG_TARGETS}) 28 | list(APPEND plugins $) 29 | endforeach() 30 | 31 | add_test(NAME ${name} COMMAND ${command} ${plugins} ${ARG_SCRIPT}) 32 | 33 | get_filename_component(AMX_PATH ${ARG_SCRIPT} DIRECTORY) 34 | set_tests_properties(${name} PROPERTIES ENVIRONMENT AMX_PATH=${AMX_PATH}) 35 | 36 | if(ARG_OUTPUT_FILE) 37 | file(READ ${ARG_OUTPUT_FILE} output) 38 | set_tests_properties(${name} PROPERTIES PASS_REGULAR_EXPRESSION ${output}) 39 | endif() 40 | 41 | if(ARG_TIMEOUT) 42 | set_tests_properties(${name} PROPERTIES TIMEOUT ${ARG_TIMEOUT}) 43 | endif() 44 | 45 | if(ARG_WORKING_DIRECTORY) 46 | set_tests_properties(${name} PROPERTIES 47 | WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY}) 48 | endif() 49 | endfunction() 50 | -------------------------------------------------------------------------------- /src/cmake/FindPawnCC.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | if(WIN32) 4 | set(_PawnCC_EXECUTABLE_NAME pawncc.exe) 5 | else() 6 | set(_PawnCC_EXECUTABLE_NAME pawncc) 7 | endif() 8 | 9 | find_file(PawnCC_EXECUTABLE ${_PawnCC_EXECUTABLE_NAME}) 10 | 11 | mark_as_advanced(PawnCC_EXECUTABLE) 12 | 13 | find_package_handle_standard_args(PawnCC 14 | FOUND_VAR PawnCC_FOUND 15 | REQUIRED_VARS PawnCC_EXECUTABLE 16 | ) 17 | -------------------------------------------------------------------------------- /src/cmake/FindPluginRunner.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | if(WIN32) 4 | set(_PluginRunner_EXECUTABLE_NAME plugin-runner.exe) 5 | else() 6 | set(_PluginRunner_EXECUTABLE_NAME plugin-runner) 7 | endif() 8 | 9 | find_file(PluginRunner_EXECUTABLE 10 | NAMES ${_PluginRunner_EXECUTABLE_NAME} 11 | HINTS ENV SAMP_SERVER_ROOT 12 | ) 13 | find_path(PluginRunner_DIR 14 | NAMES ${_PluginRunner_EXECUTABLE_NAME} 15 | HINTS ENV SAMP_SERVER_ROOT 16 | ) 17 | 18 | mark_as_advanced( 19 | PluginRunner_EXECUTABLE 20 | PluginRunner_DIR 21 | ) 22 | 23 | find_package_handle_standard_args(PluginRunner 24 | FOUND_VAR PluginRunner_FOUND 25 | REQUIRED_VARS PluginRunner_EXECUTABLE PluginRunner_DIR 26 | ) 27 | -------------------------------------------------------------------------------- /src/cmake/FindSAMPGDK.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | find_package(SAMPGDK QUIET CONFIG NAMES SAMPGDK) 4 | 5 | set(SAMPGDK_INCLUDE_DIRS ${SAMPGDK_INCLUDE_DIR}) 6 | set(SAMPGDK_LIBRARY_DIRS ${SAMPGDK_LIBRARY_DIR}) 7 | 8 | mark_as_advanced( 9 | SAMPGDK_VERSION 10 | SAMPGDK_INCLUDE_DIR 11 | SAMPGDK_LIBRARY_DIR 12 | ) 13 | 14 | find_package_handle_standard_args(SAMPGDK 15 | REQUIRED_VARS SAMPGDK_INCLUDE_DIRS SAMPGDK_LIBRARY_DIRS 16 | VERSION_VAR SAMPGDK_VERSION 17 | ) 18 | -------------------------------------------------------------------------------- /src/cmake/FindSAMPSDK.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | find_path(SAMPSDK_DIR 4 | NAMES plugin.h 5 | plugincommon.h 6 | HINTS ${SAMP_SDK_ROOT} 7 | ENV SAMP_SDK_ROOT 8 | PATH_SUFFIXES sdk SDK 9 | DOC "Path to SA-MP plugin SDK" 10 | NO_SYSTEM_ENVIRONMENT_PATH 11 | NO_CMAKE_SYSTEM_PATH 12 | ) 13 | 14 | set(SAMPSDK_INCLUDE_DIR ${SAMPSDK_DIR}) 15 | 16 | mark_as_advanced( 17 | SAMPSDK_DIR 18 | SAMPSDK_INCLUDE_DIR 19 | ) 20 | 21 | find_package_handle_standard_args(SAMPSDK 22 | REQUIRED_VARS SAMPSDK_DIR 23 | SAMPSDK_INCLUDE_DIR 24 | ) 25 | -------------------------------------------------------------------------------- /src/cmake/FindSAMPServer.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | if(WIN32) 4 | set(_SAMPServer_EXECUTABLE_NAME samp-server.exe) 5 | else() 6 | set(_SAMPServer_EXECUTABLE_NAME samp03svr) 7 | endif() 8 | 9 | find_file(SAMPServer_EXECUTABLE 10 | NAMES ${_SAMPServer_EXECUTABLE_NAME} 11 | HINTS ENV SAMP_SERVER_ROOT 12 | ) 13 | find_path(SAMPServer_DIR 14 | NAMES ${_SAMPServer_EXECUTABLE_NAME} 15 | HINTS ENV SAMP_SERVER_ROOT 16 | ) 17 | find_path(SAMPServer_INCLUDE_DIR 18 | NAMES a_samp.inc a_npc.inc 19 | HINTS ${SAMPServer_DIR}/include 20 | ${SAMPServer_DIR}/pawno/include 21 | ) 22 | 23 | mark_as_advanced( 24 | SAMPServer_EXECUTABLE 25 | SAMPServer_DIR 26 | SAMPServer_INCLUDE_DIR 27 | ) 28 | 29 | find_package_handle_standard_args(SAMPServer 30 | FOUND_VAR SAMPServer_FOUND 31 | REQUIRED_VARS SAMPServer_EXECUTABLE 32 | SAMPServer_DIR 33 | SAMPServer_INCLUDE_DIR 34 | ) 35 | -------------------------------------------------------------------------------- /src/cmake/FindSAMPServerCLI.cmake: -------------------------------------------------------------------------------- 1 | include(FindPackageHandleStandardArgs) 2 | 3 | if(WIN32) 4 | set(_SAMPServerCLI_EXECUTABLE_NAME samp-server-cli.bat 5 | samp-server-cli.exe) 6 | else() 7 | set(_SAMPServerCLI_EXECUTABLE_NAME samp-server-cli) 8 | endif() 9 | 10 | find_file(SAMPServerCLI_EXECUTABLE 11 | NAMES ${_SAMPServerCLI_EXECUTABLE_NAME} 12 | HINTS ENV SAMP_SERVER_ROOT 13 | ) 14 | find_path(SAMPServerCLI_DIR 15 | NAMES ${_SAMPServerCLI_EXECUTABLE_NAME} 16 | HINTS ENV SAMP_SERVER_ROOT 17 | ) 18 | 19 | mark_as_advanced( 20 | SAMPServerCLI_EXECUTABLE 21 | SAMPServerCLI_DIR 22 | ) 23 | 24 | find_package_handle_standard_args(SAMPServerCLI 25 | FOUND_VAR SAMPServerCLI_FOUND 26 | REQUIRED_VARS SAMPServerCLI_EXECUTABLE 27 | SAMPServerCLI_DIR 28 | ) 29 | -------------------------------------------------------------------------------- /src/cmake/LICENSE.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2014-2015 Zeex 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /src/cmake/README.md: -------------------------------------------------------------------------------- 1 | Name | Description 2 | :------------------------------------------------|:-------------------------------------------------------- 3 | [AddSAMPPlugin](AddSAMPPlugin.cmake) | Provides `add_samp_plugin()` function 4 | [AddSAMPPluginTest](AddSAMPPluginTest.cmake) | Provides `add_samp_plugin_test()` function 5 | [AddSAMPPluginTestPR](AddSAMPPluginTestPR.cmake) | Same as above but uses [plugin-runner][plugin-runner] instead of [samp-server-cli][samp-server-cli] 6 | [AMXConfig](AMXConfig.cmake) | Defines platform-specific macros expected by AMX headers 7 | [FindPawnCC](FindPawnCC.cmake) | Finds Pawn compiler executable 8 | [FindPluginRunner](FindPluginRunner.cmake) | Finds [plugin-runner][plugin-runner] executable 9 | [FindSAMPSDK](FindSAMPSDK.cmake) | Finds SA-MP plugin SDK 10 | [FindSAMPGDK](FindSAMPGDK.cmake) | Finds [GDK][sampgdk] library and headers 11 | [FindSAMPServer](FindSAMPServer.cmake) | Finds SA-MP server executable 12 | [FindSAMPServerCLI](FindSAMPServerCLI.cmake) | Finds [samp-server-cli][samp-server-cli] 13 | 14 | [sampgdk]: https://github.com/Zeex/sampgdk 15 | [samp-server-cli]: https://github.com/Zeex/samp-server-cli 16 | [plugin-runner]: https://github.com/Zeex/plugin-runner 17 | -------------------------------------------------------------------------------- /src/compilation_date.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BUILD_DEFS_H 2 | 3 | #define BUILD_DEFS_H 4 | 5 | 6 | // Example of __DATE__ string: "Jul 27 2012" 7 | // Example of __TIME__ string: "21:06:19" 8 | 9 | #define COMPUTE_BUILD_YEAR \ 10 | ( \ 11 | (__DATE__[ 7] - '0') * 1000 + \ 12 | (__DATE__[ 8] - '0') * 100 + \ 13 | (__DATE__[ 9] - '0') * 10 + \ 14 | (__DATE__[10] - '0') \ 15 | ) 16 | 17 | 18 | #define COMPUTE_BUILD_DAY \ 19 | ( \ 20 | ((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \ 21 | (__DATE__[5] - '0') \ 22 | ) 23 | 24 | 25 | #define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n') 26 | #define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F') 27 | #define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r') 28 | #define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p') 29 | #define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y') 30 | #define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n') 31 | #define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l') 32 | #define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u') 33 | #define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S') 34 | #define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O') 35 | #define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N') 36 | #define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D') 37 | 38 | 39 | #define COMPUTE_BUILD_MONTH \ 40 | ( \ 41 | (BUILD_MONTH_IS_JAN) ? 1 : \ 42 | (BUILD_MONTH_IS_FEB) ? 2 : \ 43 | (BUILD_MONTH_IS_MAR) ? 3 : \ 44 | (BUILD_MONTH_IS_APR) ? 4 : \ 45 | (BUILD_MONTH_IS_MAY) ? 5 : \ 46 | (BUILD_MONTH_IS_JUN) ? 6 : \ 47 | (BUILD_MONTH_IS_JUL) ? 7 : \ 48 | (BUILD_MONTH_IS_AUG) ? 8 : \ 49 | (BUILD_MONTH_IS_SEP) ? 9 : \ 50 | (BUILD_MONTH_IS_OCT) ? 10 : \ 51 | (BUILD_MONTH_IS_NOV) ? 11 : \ 52 | (BUILD_MONTH_IS_DEC) ? 12 : \ 53 | /* error default */ 99 \ 54 | ) 55 | 56 | #define COMPUTE_BUILD_HOUR ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0') 57 | #define COMPUTE_BUILD_MIN ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0') 58 | #define COMPUTE_BUILD_SEC ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0') 59 | 60 | 61 | #define BUILD_DATE_IS_BAD (__DATE__[0] == '?') 62 | 63 | #define BUILD_YEAR ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_YEAR) 64 | #define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH) 65 | #define BUILD_DAY ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY) 66 | 67 | #define BUILD_TIME_IS_BAD (__TIME__[0] == '?') 68 | 69 | #define BUILD_HOUR ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_HOUR) 70 | #define BUILD_MIN ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_MIN) 71 | #define BUILD_SEC ((BUILD_TIME_IS_BAD) ? 99 : COMPUTE_BUILD_SEC) 72 | 73 | 74 | #endif // BUILD_DEFS_H -------------------------------------------------------------------------------- /src/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic format arguments 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #include // std::reference_wrapper 12 | #include // std::unique_ptr 13 | #include 14 | 15 | #include "core.h" 16 | 17 | FMT_BEGIN_NAMESPACE 18 | 19 | namespace detail { 20 | 21 | template struct is_reference_wrapper : std::false_type {}; 22 | template 23 | struct is_reference_wrapper> : std::true_type {}; 24 | 25 | template const T& unwrap(const T& v) { return v; } 26 | template const T& unwrap(const std::reference_wrapper& v) { 27 | return static_cast(v); 28 | } 29 | 30 | class dynamic_arg_list { 31 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 32 | // templates it doesn't complain about inability to deduce single translation 33 | // unit for placing vtable. So storage_node_base is made a fake template. 34 | template struct node { 35 | virtual ~node() = default; 36 | std::unique_ptr> next; 37 | }; 38 | 39 | template struct typed_node : node<> { 40 | T value; 41 | 42 | template 43 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 44 | 45 | template 46 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 47 | : value(arg.data(), arg.size()) {} 48 | }; 49 | 50 | std::unique_ptr> head_; 51 | 52 | public: 53 | template const T& push(const Arg& arg) { 54 | auto new_node = std::unique_ptr>(new typed_node(arg)); 55 | auto& value = new_node->value; 56 | new_node->next = std::move(head_); 57 | head_ = std::move(new_node); 58 | return value; 59 | } 60 | }; 61 | } // namespace detail 62 | 63 | /** 64 | \rst 65 | A dynamic version of `fmt::format_arg_store`. 66 | It's equipped with a storage to potentially temporary objects which lifetimes 67 | could be shorter than the format arguments object. 68 | 69 | It can be implicitly converted into `~fmt::basic_format_args` for passing 70 | into type-erased formatting functions such as `~fmt::vformat`. 71 | \endrst 72 | */ 73 | template 74 | class dynamic_format_arg_store 75 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 76 | // Workaround a GCC template argument substitution bug. 77 | : public basic_format_args 78 | #endif 79 | { 80 | private: 81 | using char_type = typename Context::char_type; 82 | 83 | template struct need_copy { 84 | static constexpr detail::type mapped_type = 85 | detail::mapped_type_constant::value; 86 | 87 | enum { 88 | value = !(detail::is_reference_wrapper::value || 89 | std::is_same>::value || 90 | std::is_same>::value || 91 | (mapped_type != detail::type::cstring_type && 92 | mapped_type != detail::type::string_type && 93 | mapped_type != detail::type::custom_type)) 94 | }; 95 | }; 96 | 97 | template 98 | using stored_type = conditional_t< 99 | std::is_convertible>::value && 100 | !detail::is_reference_wrapper::value, 101 | std::basic_string, T>; 102 | 103 | // Storage of basic_format_arg must be contiguous. 104 | std::vector> data_; 105 | std::vector> named_info_; 106 | 107 | // Storage of arguments not fitting into basic_format_arg must grow 108 | // without relocation because items in data_ refer to it. 109 | detail::dynamic_arg_list dynamic_args_; 110 | 111 | friend class basic_format_args; 112 | 113 | unsigned long long get_types() const { 114 | return detail::is_unpacked_bit | data_.size() | 115 | (named_info_.empty() 116 | ? 0ULL 117 | : static_cast(detail::has_named_args_bit)); 118 | } 119 | 120 | const basic_format_arg* data() const { 121 | return named_info_.empty() ? data_.data() : data_.data() + 1; 122 | } 123 | 124 | template void emplace_arg(const T& arg) { 125 | data_.emplace_back(detail::make_arg(arg)); 126 | } 127 | 128 | template 129 | void emplace_arg(const detail::named_arg& arg) { 130 | if (named_info_.empty()) { 131 | constexpr const detail::named_arg_info* zero_ptr{nullptr}; 132 | data_.insert(data_.begin(), {zero_ptr, 0}); 133 | } 134 | data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); 135 | auto pop_one = [](std::vector>* data) { 136 | data->pop_back(); 137 | }; 138 | std::unique_ptr>, decltype(pop_one)> 139 | guard{&data_, pop_one}; 140 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 141 | data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; 142 | guard.release(); 143 | } 144 | 145 | public: 146 | constexpr dynamic_format_arg_store() = default; 147 | 148 | /** 149 | \rst 150 | Adds an argument into the dynamic store for later passing to a formatting 151 | function. 152 | 153 | Note that custom types and string types (but not string views) are copied 154 | into the store dynamically allocating memory if necessary. 155 | 156 | **Example**:: 157 | 158 | fmt::dynamic_format_arg_store store; 159 | store.push_back(42); 160 | store.push_back("abc"); 161 | store.push_back(1.5f); 162 | std::string result = fmt::vformat("{} and {} and {}", store); 163 | \endrst 164 | */ 165 | template void push_back(const T& arg) { 166 | if (detail::const_check(need_copy::value)) 167 | emplace_arg(dynamic_args_.push>(arg)); 168 | else 169 | emplace_arg(detail::unwrap(arg)); 170 | } 171 | 172 | /** 173 | \rst 174 | Adds a reference to the argument into the dynamic store for later passing to 175 | a formatting function. 176 | 177 | **Example**:: 178 | 179 | fmt::dynamic_format_arg_store store; 180 | char band[] = "Rolling Stones"; 181 | store.push_back(std::cref(band)); 182 | band[9] = 'c'; // Changing str affects the output. 183 | std::string result = fmt::vformat("{}", store); 184 | // result == "Rolling Scones" 185 | \endrst 186 | */ 187 | template void push_back(std::reference_wrapper arg) { 188 | static_assert( 189 | need_copy::value, 190 | "objects of built-in types and string views are always copied"); 191 | emplace_arg(arg.get()); 192 | } 193 | 194 | /** 195 | Adds named argument into the dynamic store for later passing to a formatting 196 | function. ``std::reference_wrapper`` is supported to avoid copying of the 197 | argument. The name is always copied into the store. 198 | */ 199 | template 200 | void push_back(const detail::named_arg& arg) { 201 | const char_type* arg_name = 202 | dynamic_args_.push>(arg.name).c_str(); 203 | if (detail::const_check(need_copy::value)) { 204 | emplace_arg( 205 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 206 | } else { 207 | emplace_arg(fmt::arg(arg_name, arg.value)); 208 | } 209 | } 210 | 211 | /** Erase all elements from the store */ 212 | void clear() { 213 | data_.clear(); 214 | named_info_.clear(); 215 | dynamic_args_ = detail::dynamic_arg_list(); 216 | } 217 | 218 | /** 219 | \rst 220 | Reserves space to store at least *new_cap* arguments including 221 | *new_cap_named* named arguments. 222 | \endrst 223 | */ 224 | void reserve(size_t new_cap, size_t new_cap_named) { 225 | FMT_ASSERT(new_cap >= new_cap_named, 226 | "Set of arguments includes set of named arguments"); 227 | data_.reserve(new_cap); 228 | named_info_.reserve(new_cap_named); 229 | } 230 | }; 231 | 232 | FMT_END_NAMESPACE 233 | 234 | #endif // FMT_ARGS_H_ 235 | -------------------------------------------------------------------------------- /src/fmt/compile.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - experimental format string compilation 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COMPILE_H_ 9 | #define FMT_COMPILE_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | namespace detail { 15 | 16 | template 17 | FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, 18 | counting_iterator it) { 19 | return it + (end - begin); 20 | } 21 | 22 | template class truncating_iterator_base { 23 | protected: 24 | OutputIt out_; 25 | size_t limit_; 26 | size_t count_ = 0; 27 | 28 | truncating_iterator_base() : out_(), limit_(0) {} 29 | 30 | truncating_iterator_base(OutputIt out, size_t limit) 31 | : out_(out), limit_(limit) {} 32 | 33 | public: 34 | using iterator_category = std::output_iterator_tag; 35 | using value_type = typename std::iterator_traits::value_type; 36 | using difference_type = std::ptrdiff_t; 37 | using pointer = void; 38 | using reference = void; 39 | FMT_UNCHECKED_ITERATOR(truncating_iterator_base); 40 | 41 | OutputIt base() const { return out_; } 42 | size_t count() const { return count_; } 43 | }; 44 | 45 | // An output iterator that truncates the output and counts the number of objects 46 | // written to it. 47 | template ::value_type>::type> 50 | class truncating_iterator; 51 | 52 | template 53 | class truncating_iterator 54 | : public truncating_iterator_base { 55 | mutable typename truncating_iterator_base::value_type blackhole_; 56 | 57 | public: 58 | using value_type = typename truncating_iterator_base::value_type; 59 | 60 | truncating_iterator() = default; 61 | 62 | truncating_iterator(OutputIt out, size_t limit) 63 | : truncating_iterator_base(out, limit) {} 64 | 65 | truncating_iterator& operator++() { 66 | if (this->count_++ < this->limit_) ++this->out_; 67 | return *this; 68 | } 69 | 70 | truncating_iterator operator++(int) { 71 | auto it = *this; 72 | ++*this; 73 | return it; 74 | } 75 | 76 | value_type& operator*() const { 77 | return this->count_ < this->limit_ ? *this->out_ : blackhole_; 78 | } 79 | }; 80 | 81 | template 82 | class truncating_iterator 83 | : public truncating_iterator_base { 84 | public: 85 | truncating_iterator() = default; 86 | 87 | truncating_iterator(OutputIt out, size_t limit) 88 | : truncating_iterator_base(out, limit) {} 89 | 90 | template truncating_iterator& operator=(T val) { 91 | if (this->count_++ < this->limit_) *this->out_++ = val; 92 | return *this; 93 | } 94 | 95 | truncating_iterator& operator++() { return *this; } 96 | truncating_iterator& operator++(int) { return *this; } 97 | truncating_iterator& operator*() { return *this; } 98 | }; 99 | 100 | // A compile-time string which is compiled into fast formatting code. 101 | class compiled_string {}; 102 | 103 | template 104 | struct is_compiled_string : std::is_base_of {}; 105 | 106 | /** 107 | \rst 108 | Converts a string literal *s* into a format string that will be parsed at 109 | compile time and converted into efficient formatting code. Requires C++17 110 | ``constexpr if`` compiler support. 111 | 112 | **Example**:: 113 | 114 | // Converts 42 into std::string using the most efficient method and no 115 | // runtime format string processing. 116 | std::string s = fmt::format(FMT_COMPILE("{}"), 42); 117 | \endrst 118 | */ 119 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 120 | # define FMT_COMPILE(s) \ 121 | FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) 122 | #else 123 | # define FMT_COMPILE(s) FMT_STRING(s) 124 | #endif 125 | 126 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 127 | template Str> 129 | struct udl_compiled_string : compiled_string { 130 | using char_type = Char; 131 | explicit constexpr operator basic_string_view() const { 132 | return {Str.data, N - 1}; 133 | } 134 | }; 135 | #endif 136 | 137 | template 138 | const T& first(const T& value, const Tail&...) { 139 | return value; 140 | } 141 | 142 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 143 | template struct type_list {}; 144 | 145 | // Returns a reference to the argument at index N from [first, rest...]. 146 | template 147 | constexpr const auto& get([[maybe_unused]] const T& first, 148 | [[maybe_unused]] const Args&... rest) { 149 | static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); 150 | if constexpr (N == 0) 151 | return first; 152 | else 153 | return detail::get(rest...); 154 | } 155 | 156 | template 157 | constexpr int get_arg_index_by_name(basic_string_view name, 158 | type_list) { 159 | return get_arg_index_by_name(name); 160 | } 161 | 162 | template struct get_type_impl; 163 | 164 | template struct get_type_impl> { 165 | using type = 166 | remove_cvref_t(std::declval()...))>; 167 | }; 168 | 169 | template 170 | using get_type = typename get_type_impl::type; 171 | 172 | template struct is_compiled_format : std::false_type {}; 173 | 174 | template struct text { 175 | basic_string_view data; 176 | using char_type = Char; 177 | 178 | template 179 | constexpr OutputIt format(OutputIt out, const Args&...) const { 180 | return write(out, data); 181 | } 182 | }; 183 | 184 | template 185 | struct is_compiled_format> : std::true_type {}; 186 | 187 | template 188 | constexpr text make_text(basic_string_view s, size_t pos, 189 | size_t size) { 190 | return {{&s[pos], size}}; 191 | } 192 | 193 | template struct code_unit { 194 | Char value; 195 | using char_type = Char; 196 | 197 | template 198 | constexpr OutputIt format(OutputIt out, const Args&...) const { 199 | return write(out, value); 200 | } 201 | }; 202 | 203 | // This ensures that the argument type is convertible to `const T&`. 204 | template 205 | constexpr const T& get_arg_checked(const Args&... args) { 206 | const auto& arg = detail::get(args...); 207 | if constexpr (detail::is_named_arg>()) { 208 | return arg.value; 209 | } else { 210 | return arg; 211 | } 212 | } 213 | 214 | template 215 | struct is_compiled_format> : std::true_type {}; 216 | 217 | // A replacement field that refers to argument N. 218 | template struct field { 219 | using char_type = Char; 220 | 221 | template 222 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 223 | return write(out, get_arg_checked(args...)); 224 | } 225 | }; 226 | 227 | template 228 | struct is_compiled_format> : std::true_type {}; 229 | 230 | // A replacement field that refers to argument with name. 231 | template struct runtime_named_field { 232 | using char_type = Char; 233 | basic_string_view name; 234 | 235 | template 236 | constexpr static bool try_format_argument( 237 | OutputIt& out, 238 | // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 239 | [[maybe_unused]] basic_string_view arg_name, const T& arg) { 240 | if constexpr (is_named_arg::type>::value) { 241 | if (arg_name == arg.name) { 242 | out = write(out, arg.value); 243 | return true; 244 | } 245 | } 246 | return false; 247 | } 248 | 249 | template 250 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 251 | bool found = (try_format_argument(out, name, args) || ...); 252 | if (!found) { 253 | FMT_THROW(format_error("argument with specified name is not found")); 254 | } 255 | return out; 256 | } 257 | }; 258 | 259 | template 260 | struct is_compiled_format> : std::true_type {}; 261 | 262 | // A replacement field that refers to argument N and has format specifiers. 263 | template struct spec_field { 264 | using char_type = Char; 265 | formatter fmt; 266 | 267 | template 268 | constexpr FMT_INLINE OutputIt format(OutputIt out, 269 | const Args&... args) const { 270 | const auto& vargs = 271 | fmt::make_format_args>(args...); 272 | basic_format_context ctx(out, vargs); 273 | return fmt.format(get_arg_checked(args...), ctx); 274 | } 275 | }; 276 | 277 | template 278 | struct is_compiled_format> : std::true_type {}; 279 | 280 | template struct concat { 281 | L lhs; 282 | R rhs; 283 | using char_type = typename L::char_type; 284 | 285 | template 286 | constexpr OutputIt format(OutputIt out, const Args&... args) const { 287 | out = lhs.format(out, args...); 288 | return rhs.format(out, args...); 289 | } 290 | }; 291 | 292 | template 293 | struct is_compiled_format> : std::true_type {}; 294 | 295 | template 296 | constexpr concat make_concat(L lhs, R rhs) { 297 | return {lhs, rhs}; 298 | } 299 | 300 | struct unknown_format {}; 301 | 302 | template 303 | constexpr size_t parse_text(basic_string_view str, size_t pos) { 304 | for (size_t size = str.size(); pos != size; ++pos) { 305 | if (str[pos] == '{' || str[pos] == '}') break; 306 | } 307 | return pos; 308 | } 309 | 310 | template 311 | constexpr auto compile_format_string(S format_str); 312 | 313 | template 314 | constexpr auto parse_tail(T head, S format_str) { 315 | if constexpr (POS != 316 | basic_string_view(format_str).size()) { 317 | constexpr auto tail = compile_format_string(format_str); 318 | if constexpr (std::is_same, 319 | unknown_format>()) 320 | return tail; 321 | else 322 | return make_concat(head, tail); 323 | } else { 324 | return head; 325 | } 326 | } 327 | 328 | template struct parse_specs_result { 329 | formatter fmt; 330 | size_t end; 331 | int next_arg_id; 332 | }; 333 | 334 | constexpr int manual_indexing_id = -1; 335 | 336 | template 337 | constexpr parse_specs_result parse_specs(basic_string_view str, 338 | size_t pos, int next_arg_id) { 339 | str.remove_prefix(pos); 340 | auto ctx = compile_parse_context(str, max_value(), nullptr, {}, 341 | next_arg_id); 342 | auto f = formatter(); 343 | auto end = f.parse(ctx); 344 | return {f, pos + fmt::detail::to_unsigned(end - str.data()), 345 | next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; 346 | } 347 | 348 | template struct arg_id_handler { 349 | arg_ref arg_id; 350 | 351 | constexpr int operator()() { 352 | FMT_ASSERT(false, "handler cannot be used with automatic indexing"); 353 | return 0; 354 | } 355 | constexpr int operator()(int id) { 356 | arg_id = arg_ref(id); 357 | return 0; 358 | } 359 | constexpr int operator()(basic_string_view id) { 360 | arg_id = arg_ref(id); 361 | return 0; 362 | } 363 | 364 | constexpr void on_error(const char* message) { 365 | FMT_THROW(format_error(message)); 366 | } 367 | }; 368 | 369 | template struct parse_arg_id_result { 370 | arg_ref arg_id; 371 | const Char* arg_id_end; 372 | }; 373 | 374 | template 375 | constexpr auto parse_arg_id(const Char* begin, const Char* end) { 376 | auto handler = arg_id_handler{arg_ref{}}; 377 | auto arg_id_end = parse_arg_id(begin, end, handler); 378 | return parse_arg_id_result{handler.arg_id, arg_id_end}; 379 | } 380 | 381 | template struct field_type { 382 | using type = remove_cvref_t; 383 | }; 384 | 385 | template 386 | struct field_type::value>> { 387 | using type = remove_cvref_t; 388 | }; 389 | 390 | template 392 | constexpr auto parse_replacement_field_then_tail(S format_str) { 393 | using char_type = typename S::char_type; 394 | constexpr auto str = basic_string_view(format_str); 395 | constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); 396 | if constexpr (c == '}') { 397 | return parse_tail( 398 | field::type, ARG_INDEX>(), 399 | format_str); 400 | } else if constexpr (c != ':') { 401 | FMT_THROW(format_error("expected ':'")); 402 | } else { 403 | constexpr auto result = parse_specs::type>( 404 | str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); 405 | if constexpr (result.end >= str.size() || str[result.end] != '}') { 406 | FMT_THROW(format_error("expected '}'")); 407 | return 0; 408 | } else { 409 | return parse_tail( 410 | spec_field::type, ARG_INDEX>{ 411 | result.fmt}, 412 | format_str); 413 | } 414 | } 415 | } 416 | 417 | // Compiles a non-empty format string and returns the compiled representation 418 | // or unknown_format() on unrecognized input. 419 | template 420 | constexpr auto compile_format_string(S format_str) { 421 | using char_type = typename S::char_type; 422 | constexpr auto str = basic_string_view(format_str); 423 | if constexpr (str[POS] == '{') { 424 | if constexpr (POS + 1 == str.size()) 425 | FMT_THROW(format_error("unmatched '{' in format string")); 426 | if constexpr (str[POS + 1] == '{') { 427 | return parse_tail(make_text(str, POS, 1), format_str); 428 | } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { 429 | static_assert(ID != manual_indexing_id, 430 | "cannot switch from manual to automatic argument indexing"); 431 | constexpr auto next_id = 432 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 433 | return parse_replacement_field_then_tail, Args, 434 | POS + 1, ID, next_id>( 435 | format_str); 436 | } else { 437 | constexpr auto arg_id_result = 438 | parse_arg_id(str.data() + POS + 1, str.data() + str.size()); 439 | constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); 440 | constexpr char_type c = 441 | arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); 442 | static_assert(c == '}' || c == ':', "missing '}' in format string"); 443 | if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { 444 | static_assert( 445 | ID == manual_indexing_id || ID == 0, 446 | "cannot switch from automatic to manual argument indexing"); 447 | constexpr auto arg_index = arg_id_result.arg_id.val.index; 448 | return parse_replacement_field_then_tail, 449 | Args, arg_id_end_pos, 450 | arg_index, manual_indexing_id>( 451 | format_str); 452 | } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { 453 | constexpr auto arg_index = 454 | get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); 455 | if constexpr (arg_index != invalid_arg_index) { 456 | constexpr auto next_id = 457 | ID != manual_indexing_id ? ID + 1 : manual_indexing_id; 458 | return parse_replacement_field_then_tail< 459 | decltype(get_type::value), Args, arg_id_end_pos, 460 | arg_index, next_id>(format_str); 461 | } else { 462 | if constexpr (c == '}') { 463 | return parse_tail( 464 | runtime_named_field{arg_id_result.arg_id.val.name}, 465 | format_str); 466 | } else if constexpr (c == ':') { 467 | return unknown_format(); // no type info for specs parsing 468 | } 469 | } 470 | } 471 | } 472 | } else if constexpr (str[POS] == '}') { 473 | if constexpr (POS + 1 == str.size()) 474 | FMT_THROW(format_error("unmatched '}' in format string")); 475 | return parse_tail(make_text(str, POS, 1), format_str); 476 | } else { 477 | constexpr auto end = parse_text(str, POS + 1); 478 | if constexpr (end - POS > 1) { 479 | return parse_tail(make_text(str, POS, end - POS), 480 | format_str); 481 | } else { 482 | return parse_tail(code_unit{str[POS]}, 483 | format_str); 484 | } 485 | } 486 | } 487 | 488 | template ::value)> 490 | constexpr auto compile(S format_str) { 491 | constexpr auto str = basic_string_view(format_str); 492 | if constexpr (str.size() == 0) { 493 | return detail::make_text(str, 0, 0); 494 | } else { 495 | constexpr auto result = 496 | detail::compile_format_string, 0, 0>( 497 | format_str); 498 | return result; 499 | } 500 | } 501 | #endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 502 | } // namespace detail 503 | 504 | FMT_MODULE_EXPORT_BEGIN 505 | 506 | #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) 507 | 508 | template ::value)> 511 | FMT_INLINE std::basic_string format(const CompiledFormat& cf, 512 | const Args&... args) { 513 | auto s = std::basic_string(); 514 | cf.format(std::back_inserter(s), args...); 515 | return s; 516 | } 517 | 518 | template ::value)> 520 | constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, 521 | const Args&... args) { 522 | return cf.format(out, args...); 523 | } 524 | 525 | template ::value)> 527 | FMT_INLINE std::basic_string format(const S&, 528 | Args&&... args) { 529 | if constexpr (std::is_same::value) { 530 | constexpr auto str = basic_string_view(S()); 531 | if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { 532 | const auto& first = detail::first(args...); 533 | if constexpr (detail::is_named_arg< 534 | remove_cvref_t>::value) { 535 | return fmt::to_string(first.value); 536 | } else { 537 | return fmt::to_string(first); 538 | } 539 | } 540 | } 541 | constexpr auto compiled = detail::compile(S()); 542 | if constexpr (std::is_same, 543 | detail::unknown_format>()) { 544 | return fmt::format( 545 | static_cast>(S()), 546 | std::forward(args)...); 547 | } else { 548 | return fmt::format(compiled, std::forward(args)...); 549 | } 550 | } 551 | 552 | template ::value)> 554 | FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { 555 | constexpr auto compiled = detail::compile(S()); 556 | if constexpr (std::is_same, 557 | detail::unknown_format>()) { 558 | return fmt::format_to( 559 | out, static_cast>(S()), 560 | std::forward(args)...); 561 | } else { 562 | return fmt::format_to(out, compiled, std::forward(args)...); 563 | } 564 | } 565 | #endif 566 | 567 | template ::value)> 569 | format_to_n_result format_to_n(OutputIt out, size_t n, 570 | const S& format_str, Args&&... args) { 571 | auto it = fmt::format_to(detail::truncating_iterator(out, n), 572 | format_str, std::forward(args)...); 573 | return {it.base(), it.count()}; 574 | } 575 | 576 | template ::value)> 578 | FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, 579 | const Args&... args) { 580 | return fmt::format_to(detail::counting_iterator(), format_str, args...) 581 | .count(); 582 | } 583 | 584 | template ::value)> 586 | void print(std::FILE* f, const S& format_str, const Args&... args) { 587 | memory_buffer buffer; 588 | fmt::format_to(std::back_inserter(buffer), format_str, args...); 589 | detail::print(f, {buffer.data(), buffer.size()}); 590 | } 591 | 592 | template ::value)> 594 | void print(const S& format_str, const Args&... args) { 595 | print(stdout, format_str, args...); 596 | } 597 | 598 | #if FMT_USE_NONTYPE_TEMPLATE_ARGS 599 | inline namespace literals { 600 | template constexpr auto operator""_cf() { 601 | using char_t = remove_cvref_t; 602 | return detail::udl_compiled_string(); 604 | } 605 | } // namespace literals 606 | #endif 607 | 608 | FMT_MODULE_EXPORT_END 609 | FMT_END_NAMESPACE 610 | 611 | #endif // FMT_COMPILE_H_ 612 | -------------------------------------------------------------------------------- /src/fmt/os.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional OS-specific functionality 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OS_H_ 9 | #define FMT_OS_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include // std::system_error 15 | 16 | #if defined __APPLE__ || defined(__FreeBSD__) 17 | # include // for LC_NUMERIC_MASK on OS X 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | #ifndef FMT_USE_FCNTL 23 | // UWP doesn't provide _pipe. 24 | # if FMT_HAS_INCLUDE("winapifamily.h") 25 | # include 26 | # endif 27 | # if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ 28 | defined(__linux__)) && \ 29 | (!defined(WINAPI_FAMILY) || \ 30 | (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 31 | # include // for O_RDONLY 32 | # define FMT_USE_FCNTL 1 33 | # else 34 | # define FMT_USE_FCNTL 0 35 | # endif 36 | #endif 37 | 38 | #ifndef FMT_POSIX 39 | # if defined(_WIN32) && !defined(__MINGW32__) 40 | // Fix warnings about deprecated symbols. 41 | # define FMT_POSIX(call) _##call 42 | # else 43 | # define FMT_POSIX(call) call 44 | # endif 45 | #endif 46 | 47 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 48 | #ifdef FMT_SYSTEM 49 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 50 | #else 51 | # define FMT_SYSTEM(call) ::call 52 | # ifdef _WIN32 53 | // Fix warnings about deprecated symbols. 54 | # define FMT_POSIX_CALL(call) ::_##call 55 | # else 56 | # define FMT_POSIX_CALL(call) ::call 57 | # endif 58 | #endif 59 | 60 | // Retries the expression while it evaluates to error_result and errno 61 | // equals to EINTR. 62 | #ifndef _WIN32 63 | # define FMT_RETRY_VAL(result, expression, error_result) \ 64 | do { \ 65 | (result) = (expression); \ 66 | } while ((result) == (error_result) && errno == EINTR) 67 | #else 68 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 69 | #endif 70 | 71 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 72 | 73 | FMT_BEGIN_NAMESPACE 74 | FMT_MODULE_EXPORT_BEGIN 75 | 76 | /** 77 | \rst 78 | A reference to a null-terminated string. It can be constructed from a C 79 | string or ``std::string``. 80 | 81 | You can use one of the following type aliases for common character types: 82 | 83 | +---------------+-----------------------------+ 84 | | Type | Definition | 85 | +===============+=============================+ 86 | | cstring_view | basic_cstring_view | 87 | +---------------+-----------------------------+ 88 | | wcstring_view | basic_cstring_view | 89 | +---------------+-----------------------------+ 90 | 91 | This class is most useful as a parameter type to allow passing 92 | different types of strings to a function, for example:: 93 | 94 | template 95 | std::string format(cstring_view format_str, const Args & ... args); 96 | 97 | format("{}", 42); 98 | format(std::string("{}"), 42); 99 | \endrst 100 | */ 101 | template class basic_cstring_view { 102 | private: 103 | const Char* data_; 104 | 105 | public: 106 | /** Constructs a string reference object from a C string. */ 107 | basic_cstring_view(const Char* s) : data_(s) {} 108 | 109 | /** 110 | \rst 111 | Constructs a string reference from an ``std::string`` object. 112 | \endrst 113 | */ 114 | basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} 115 | 116 | /** Returns the pointer to a C string. */ 117 | const Char* c_str() const { return data_; } 118 | }; 119 | 120 | using cstring_view = basic_cstring_view; 121 | using wcstring_view = basic_cstring_view; 122 | 123 | template struct formatter { 124 | template 125 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 126 | return ctx.begin(); 127 | } 128 | 129 | template 130 | FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const 131 | -> decltype(ctx.out()) { 132 | auto out = ctx.out(); 133 | out = detail::write_bytes(out, ec.category().name(), 134 | basic_format_specs()); 135 | out = detail::write(out, Char(':')); 136 | out = detail::write(out, ec.value()); 137 | return out; 138 | } 139 | }; 140 | 141 | #ifdef _WIN32 142 | FMT_API const std::error_category& system_category() noexcept; 143 | 144 | FMT_BEGIN_DETAIL_NAMESPACE 145 | // A converter from UTF-16 to UTF-8. 146 | // It is only provided for Windows since other systems support UTF-8 natively. 147 | class utf16_to_utf8 { 148 | private: 149 | memory_buffer buffer_; 150 | 151 | public: 152 | utf16_to_utf8() {} 153 | FMT_API explicit utf16_to_utf8(basic_string_view s); 154 | operator string_view() const { return string_view(&buffer_[0], size()); } 155 | size_t size() const { return buffer_.size() - 1; } 156 | const char* c_str() const { return &buffer_[0]; } 157 | std::string str() const { return std::string(&buffer_[0], size()); } 158 | 159 | // Performs conversion returning a system error code instead of 160 | // throwing exception on conversion error. This method may still throw 161 | // in case of memory allocation error. 162 | FMT_API int convert(basic_string_view s); 163 | }; 164 | 165 | FMT_API void format_windows_error(buffer& out, int error_code, 166 | const char* message) noexcept; 167 | FMT_END_DETAIL_NAMESPACE 168 | 169 | FMT_API std::system_error vwindows_error(int error_code, string_view format_str, 170 | format_args args); 171 | 172 | /** 173 | \rst 174 | Constructs a :class:`std::system_error` object with the description 175 | of the form 176 | 177 | .. parsed-literal:: 178 | **: ** 179 | 180 | where ** is the formatted message and ** is the 181 | system message corresponding to the error code. 182 | *error_code* is a Windows error code as given by ``GetLastError``. 183 | If *error_code* is not a valid error code such as -1, the system message 184 | will look like "error -1". 185 | 186 | **Example**:: 187 | 188 | // This throws a system_error with the description 189 | // cannot open file 'madeup': The system cannot find the file specified. 190 | // or similar (system message may vary). 191 | const char *filename = "madeup"; 192 | LPOFSTRUCT of = LPOFSTRUCT(); 193 | HFILE file = OpenFile(filename, &of, OF_READ); 194 | if (file == HFILE_ERROR) { 195 | throw fmt::windows_error(GetLastError(), 196 | "cannot open file '{}'", filename); 197 | } 198 | \endrst 199 | */ 200 | template 201 | std::system_error windows_error(int error_code, string_view message, 202 | const Args&... args) { 203 | return vwindows_error(error_code, message, fmt::make_format_args(args...)); 204 | } 205 | 206 | // Reports a Windows error without throwing an exception. 207 | // Can be used to report errors from destructors. 208 | FMT_API void report_windows_error(int error_code, const char* message) noexcept; 209 | #else 210 | inline const std::error_category& system_category() noexcept { 211 | return std::system_category(); 212 | } 213 | #endif // _WIN32 214 | 215 | // std::system is not available on some platforms such as iOS (#2248). 216 | #ifdef __OSX__ 217 | template > 218 | void say(const S& format_str, Args&&... args) { 219 | std::system(format("say \"{}\"", format(format_str, args...)).c_str()); 220 | } 221 | #endif 222 | 223 | // A buffered file. 224 | class buffered_file { 225 | private: 226 | FILE* file_; 227 | 228 | friend class file; 229 | 230 | explicit buffered_file(FILE* f) : file_(f) {} 231 | 232 | public: 233 | buffered_file(const buffered_file&) = delete; 234 | void operator=(const buffered_file&) = delete; 235 | 236 | // Constructs a buffered_file object which doesn't represent any file. 237 | buffered_file() noexcept : file_(nullptr) {} 238 | 239 | // Destroys the object closing the file it represents if any. 240 | FMT_API ~buffered_file() noexcept; 241 | 242 | public: 243 | buffered_file(buffered_file&& other) noexcept : file_(other.file_) { 244 | other.file_ = nullptr; 245 | } 246 | 247 | buffered_file& operator=(buffered_file&& other) { 248 | close(); 249 | file_ = other.file_; 250 | other.file_ = nullptr; 251 | return *this; 252 | } 253 | 254 | // Opens a file. 255 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 256 | 257 | // Closes the file. 258 | FMT_API void close(); 259 | 260 | // Returns the pointer to a FILE object representing this file. 261 | FILE* get() const noexcept { return file_; } 262 | 263 | FMT_API int descriptor() const; 264 | 265 | void vprint(string_view format_str, format_args args) { 266 | fmt::vprint(file_, format_str, args); 267 | } 268 | 269 | template 270 | inline void print(string_view format_str, const Args&... args) { 271 | vprint(format_str, fmt::make_format_args(args...)); 272 | } 273 | }; 274 | 275 | #if FMT_USE_FCNTL 276 | // A file. Closed file is represented by a file object with descriptor -1. 277 | // Methods that are not declared with noexcept may throw 278 | // fmt::system_error in case of failure. Note that some errors such as 279 | // closing the file multiple times will cause a crash on Windows rather 280 | // than an exception. You can get standard behavior by overriding the 281 | // invalid parameter handler with _set_invalid_parameter_handler. 282 | class FMT_API file { 283 | private: 284 | int fd_; // File descriptor. 285 | 286 | // Constructs a file object with a given descriptor. 287 | explicit file(int fd) : fd_(fd) {} 288 | 289 | public: 290 | // Possible values for the oflag argument to the constructor. 291 | enum { 292 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 293 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 294 | RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. 295 | CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. 296 | APPEND = FMT_POSIX(O_APPEND), // Open in append mode. 297 | TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. 298 | }; 299 | 300 | // Constructs a file object which doesn't represent any file. 301 | file() noexcept : fd_(-1) {} 302 | 303 | // Opens a file and constructs a file object representing this file. 304 | file(cstring_view path, int oflag); 305 | 306 | public: 307 | file(const file&) = delete; 308 | void operator=(const file&) = delete; 309 | 310 | file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } 311 | 312 | // Move assignment is not noexcept because close may throw. 313 | file& operator=(file&& other) { 314 | close(); 315 | fd_ = other.fd_; 316 | other.fd_ = -1; 317 | return *this; 318 | } 319 | 320 | // Destroys the object closing the file it represents if any. 321 | ~file() noexcept; 322 | 323 | // Returns the file descriptor. 324 | int descriptor() const noexcept { return fd_; } 325 | 326 | // Closes the file. 327 | void close(); 328 | 329 | // Returns the file size. The size has signed type for consistency with 330 | // stat::st_size. 331 | long long size() const; 332 | 333 | // Attempts to read count bytes from the file into the specified buffer. 334 | size_t read(void* buffer, size_t count); 335 | 336 | // Attempts to write count bytes from the specified buffer to the file. 337 | size_t write(const void* buffer, size_t count); 338 | 339 | // Duplicates a file descriptor with the dup function and returns 340 | // the duplicate as a file object. 341 | static file dup(int fd); 342 | 343 | // Makes fd be the copy of this file descriptor, closing fd first if 344 | // necessary. 345 | void dup2(int fd); 346 | 347 | // Makes fd be the copy of this file descriptor, closing fd first if 348 | // necessary. 349 | void dup2(int fd, std::error_code& ec) noexcept; 350 | 351 | // Creates a pipe setting up read_end and write_end file objects for reading 352 | // and writing respectively. 353 | static void pipe(file& read_end, file& write_end); 354 | 355 | // Creates a buffered_file object associated with this file and detaches 356 | // this file object from the file. 357 | buffered_file fdopen(const char* mode); 358 | }; 359 | 360 | // Returns the memory page size. 361 | long getpagesize(); 362 | 363 | FMT_BEGIN_DETAIL_NAMESPACE 364 | 365 | struct buffer_size { 366 | buffer_size() = default; 367 | size_t value = 0; 368 | buffer_size operator=(size_t val) const { 369 | auto bs = buffer_size(); 370 | bs.value = val; 371 | return bs; 372 | } 373 | }; 374 | 375 | struct ostream_params { 376 | int oflag = file::WRONLY | file::CREATE | file::TRUNC; 377 | size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; 378 | 379 | ostream_params() {} 380 | 381 | template 382 | ostream_params(T... params, int new_oflag) : ostream_params(params...) { 383 | oflag = new_oflag; 384 | } 385 | 386 | template 387 | ostream_params(T... params, detail::buffer_size bs) 388 | : ostream_params(params...) { 389 | this->buffer_size = bs.value; 390 | } 391 | 392 | // Intel has a bug that results in failure to deduce a constructor 393 | // for empty parameter packs. 394 | # if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 395 | ostream_params(int new_oflag) : oflag(new_oflag) {} 396 | ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} 397 | # endif 398 | }; 399 | 400 | FMT_END_DETAIL_NAMESPACE 401 | 402 | // Added {} below to work around default constructor error known to 403 | // occur in Xcode versions 7.2.1 and 8.2.1. 404 | constexpr detail::buffer_size buffer_size{}; 405 | 406 | /** A fast output stream which is not thread-safe. */ 407 | class FMT_API ostream final : private detail::buffer { 408 | private: 409 | file file_; 410 | 411 | void grow(size_t) override; 412 | 413 | ostream(cstring_view path, const detail::ostream_params& params) 414 | : file_(path, params.oflag) { 415 | set(new char[params.buffer_size], params.buffer_size); 416 | } 417 | 418 | public: 419 | ostream(ostream&& other) 420 | : detail::buffer(other.data(), other.size(), other.capacity()), 421 | file_(std::move(other.file_)) { 422 | other.clear(); 423 | other.set(nullptr, 0); 424 | } 425 | ~ostream() { 426 | flush(); 427 | delete[] data(); 428 | } 429 | 430 | void flush() { 431 | if (size() == 0) return; 432 | file_.write(data(), size()); 433 | clear(); 434 | } 435 | 436 | template 437 | friend ostream output_file(cstring_view path, T... params); 438 | 439 | void close() { 440 | flush(); 441 | file_.close(); 442 | } 443 | 444 | /** 445 | Formats ``args`` according to specifications in ``fmt`` and writes the 446 | output to the file. 447 | */ 448 | template void print(format_string fmt, T&&... args) { 449 | vformat_to(detail::buffer_appender(*this), fmt, 450 | fmt::make_format_args(args...)); 451 | } 452 | }; 453 | 454 | /** 455 | \rst 456 | Opens a file for writing. Supported parameters passed in *params*: 457 | 458 | * ````: Flags passed to `open 459 | `_ 460 | (``file::WRONLY | file::CREATE | file::TRUNC`` by default) 461 | * ``buffer_size=``: Output buffer size 462 | 463 | **Example**:: 464 | 465 | auto out = fmt::output_file("guide.txt"); 466 | out.print("Don't {}", "Panic"); 467 | \endrst 468 | */ 469 | template 470 | inline ostream output_file(cstring_view path, T... params) { 471 | return {path, detail::ostream_params(params...)}; 472 | } 473 | #endif // FMT_USE_FCNTL 474 | 475 | FMT_MODULE_EXPORT_END 476 | FMT_END_NAMESPACE 477 | 478 | #endif // FMT_OS_H_ 479 | -------------------------------------------------------------------------------- /src/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include 12 | #include 13 | #if defined(_WIN32) && defined(__GLIBCXX__) 14 | # include 15 | # include 16 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 17 | # include <__std_stream> 18 | #endif 19 | 20 | #include "format.h" 21 | 22 | FMT_BEGIN_NAMESPACE 23 | 24 | template class basic_printf_context; 25 | 26 | namespace detail { 27 | 28 | // Checks if T has a user-defined operator<<. 29 | template 30 | class is_streamable { 31 | private: 32 | template 33 | static auto test(int) 34 | -> bool_constant&>() 35 | << std::declval()) != 0>; 36 | 37 | template static auto test(...) -> std::false_type; 38 | 39 | using result = decltype(test(0)); 40 | 41 | public: 42 | is_streamable() = default; 43 | 44 | static const bool value = result::value; 45 | }; 46 | 47 | // Formatting of built-in types and arrays is intentionally disabled because 48 | // it's handled by standard (non-ostream) formatters. 49 | template 50 | struct is_streamable< 51 | T, Char, 52 | enable_if_t< 53 | std::is_arithmetic::value || std::is_array::value || 54 | std::is_pointer::value || std::is_same::value || 55 | std::is_convertible>::value || 56 | std::is_same>::value || 57 | (std::is_convertible::value && !std::is_enum::value)>> 58 | : std::false_type {}; 59 | 60 | // Generate a unique explicit instantion in every translation unit using a tag 61 | // type in an anonymous namespace. 62 | namespace { 63 | struct file_access_tag {}; 64 | } // namespace 65 | template 66 | class file_access { 67 | friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } 68 | }; 69 | 70 | #if FMT_MSC_VERSION 71 | template class file_access; 73 | auto get_file(std::filebuf&) -> FILE*; 74 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 75 | template class file_access, 76 | &std::__stdoutbuf::__file_>; 77 | auto get_file(std::__stdoutbuf&) -> FILE*; 78 | #endif 79 | 80 | inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { 81 | #if FMT_MSC_VERSION 82 | if (auto* buf = dynamic_cast(os.rdbuf())) 83 | if (FILE* f = get_file(*buf)) return write_console(f, data); 84 | #elif defined(_WIN32) && defined(__GLIBCXX__) 85 | auto* rdbuf = os.rdbuf(); 86 | FILE* c_file; 87 | if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) 88 | c_file = fbuf->file(); 89 | else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) 90 | c_file = fbuf->file(); 91 | else 92 | return false; 93 | if (c_file) return write_console(c_file, data); 94 | #elif defined(_WIN32) && defined(_LIBCPP_VERSION) 95 | if (auto* buf = dynamic_cast*>(os.rdbuf())) 96 | if (FILE* f = get_file(*buf)) return write_console(f, data); 97 | #else 98 | ignore_unused(os, data); 99 | #endif 100 | return false; 101 | } 102 | inline bool write_ostream_unicode(std::wostream&, 103 | fmt::basic_string_view) { 104 | return false; 105 | } 106 | 107 | // Write the content of buf to os. 108 | // It is a separate function rather than a part of vprint to simplify testing. 109 | template 110 | void write_buffer(std::basic_ostream& os, buffer& buf) { 111 | const Char* buf_data = buf.data(); 112 | using unsigned_streamsize = std::make_unsigned::type; 113 | unsigned_streamsize size = buf.size(); 114 | unsigned_streamsize max_size = to_unsigned(max_value()); 115 | do { 116 | unsigned_streamsize n = size <= max_size ? size : max_size; 117 | os.write(buf_data, static_cast(n)); 118 | buf_data += n; 119 | size -= n; 120 | } while (size != 0); 121 | } 122 | 123 | template 124 | void format_value(buffer& buf, const T& value, 125 | locale_ref loc = locale_ref()) { 126 | auto&& format_buf = formatbuf>(buf); 127 | auto&& output = std::basic_ostream(&format_buf); 128 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 129 | if (loc) output.imbue(loc.get()); 130 | #endif 131 | output << value; 132 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 133 | } 134 | 135 | template struct streamed_view { const T& value; }; 136 | 137 | } // namespace detail 138 | 139 | // Formats an object of type T that has an overloaded ostream operator<<. 140 | template 141 | struct basic_ostream_formatter : formatter, Char> { 142 | void set_debug_format() = delete; 143 | 144 | template 145 | auto format(const T& value, basic_format_context& ctx) const 146 | -> OutputIt { 147 | auto buffer = basic_memory_buffer(); 148 | format_value(buffer, value, ctx.locale()); 149 | return formatter, Char>::format( 150 | {buffer.data(), buffer.size()}, ctx); 151 | } 152 | }; 153 | 154 | using ostream_formatter = basic_ostream_formatter; 155 | 156 | template 157 | struct formatter, Char> 158 | : basic_ostream_formatter { 159 | template 160 | auto format(detail::streamed_view view, 161 | basic_format_context& ctx) const -> OutputIt { 162 | return basic_ostream_formatter::format(view.value, ctx); 163 | } 164 | }; 165 | 166 | /** 167 | \rst 168 | Returns a view that formats `value` via an ostream ``operator<<``. 169 | 170 | **Example**:: 171 | 172 | fmt::print("Current thread id: {}\n", 173 | fmt::streamed(std::this_thread::get_id())); 174 | \endrst 175 | */ 176 | template 177 | auto streamed(const T& value) -> detail::streamed_view { 178 | return {value}; 179 | } 180 | 181 | namespace detail { 182 | 183 | // Formats an object of type T that has an overloaded ostream operator<<. 184 | template 185 | struct fallback_formatter::value>> 186 | : basic_ostream_formatter { 187 | using basic_ostream_formatter::format; 188 | }; 189 | 190 | inline void vprint_directly(std::ostream& os, string_view format_str, 191 | format_args args) { 192 | auto buffer = memory_buffer(); 193 | detail::vformat_to(buffer, format_str, args); 194 | detail::write_buffer(os, buffer); 195 | } 196 | 197 | } // namespace detail 198 | 199 | FMT_MODULE_EXPORT template 200 | void vprint(std::basic_ostream& os, 201 | basic_string_view> format_str, 202 | basic_format_args>> args) { 203 | auto buffer = basic_memory_buffer(); 204 | detail::vformat_to(buffer, format_str, args); 205 | if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; 206 | detail::write_buffer(os, buffer); 207 | } 208 | 209 | /** 210 | \rst 211 | Prints formatted data to the stream *os*. 212 | 213 | **Example**:: 214 | 215 | fmt::print(cerr, "Don't {}!", "panic"); 216 | \endrst 217 | */ 218 | FMT_MODULE_EXPORT template 219 | void print(std::ostream& os, format_string fmt, T&&... args) { 220 | const auto& vargs = fmt::make_format_args(args...); 221 | if (detail::is_utf8()) 222 | vprint(os, fmt, vargs); 223 | else 224 | detail::vprint_directly(os, fmt, vargs); 225 | } 226 | 227 | FMT_MODULE_EXPORT 228 | template 229 | void print(std::wostream& os, 230 | basic_format_string...> fmt, 231 | Args&&... args) { 232 | vprint(os, fmt, fmt::make_format_args>(args...)); 233 | } 234 | 235 | FMT_END_NAMESPACE 236 | 237 | #endif // FMT_OSTREAM_H_ 238 | -------------------------------------------------------------------------------- /src/fmt/printf.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - legacy printf implementation 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_PRINTF_H_ 9 | #define FMT_PRINTF_H_ 10 | 11 | #include // std::max 12 | #include // std::numeric_limits 13 | 14 | #include "format.h" 15 | 16 | FMT_BEGIN_NAMESPACE 17 | FMT_MODULE_EXPORT_BEGIN 18 | 19 | template struct printf_formatter { printf_formatter() = delete; }; 20 | 21 | template 22 | class basic_printf_parse_context : public basic_format_parse_context { 23 | using basic_format_parse_context::basic_format_parse_context; 24 | }; 25 | 26 | template class basic_printf_context { 27 | private: 28 | OutputIt out_; 29 | basic_format_args args_; 30 | 31 | public: 32 | using char_type = Char; 33 | using format_arg = basic_format_arg; 34 | using parse_context_type = basic_printf_parse_context; 35 | template using formatter_type = printf_formatter; 36 | 37 | /** 38 | \rst 39 | Constructs a ``printf_context`` object. References to the arguments are 40 | stored in the context object so make sure they have appropriate lifetimes. 41 | \endrst 42 | */ 43 | basic_printf_context(OutputIt out, 44 | basic_format_args args) 45 | : out_(out), args_(args) {} 46 | 47 | OutputIt out() { return out_; } 48 | void advance_to(OutputIt it) { out_ = it; } 49 | 50 | detail::locale_ref locale() { return {}; } 51 | 52 | format_arg arg(int id) const { return args_.get(id); } 53 | 54 | FMT_CONSTEXPR void on_error(const char* message) { 55 | detail::error_handler().on_error(message); 56 | } 57 | }; 58 | 59 | FMT_BEGIN_DETAIL_NAMESPACE 60 | 61 | // Checks if a value fits in int - used to avoid warnings about comparing 62 | // signed and unsigned integers. 63 | template struct int_checker { 64 | template static bool fits_in_int(T value) { 65 | unsigned max = max_value(); 66 | return value <= max; 67 | } 68 | static bool fits_in_int(bool) { return true; } 69 | }; 70 | 71 | template <> struct int_checker { 72 | template static bool fits_in_int(T value) { 73 | return value >= (std::numeric_limits::min)() && 74 | value <= max_value(); 75 | } 76 | static bool fits_in_int(int) { return true; } 77 | }; 78 | 79 | class printf_precision_handler { 80 | public: 81 | template ::value)> 82 | int operator()(T value) { 83 | if (!int_checker::is_signed>::fits_in_int(value)) 84 | FMT_THROW(format_error("number is too big")); 85 | return (std::max)(static_cast(value), 0); 86 | } 87 | 88 | template ::value)> 89 | int operator()(T) { 90 | FMT_THROW(format_error("precision is not integer")); 91 | return 0; 92 | } 93 | }; 94 | 95 | // An argument visitor that returns true iff arg is a zero integer. 96 | class is_zero_int { 97 | public: 98 | template ::value)> 99 | bool operator()(T value) { 100 | return value == 0; 101 | } 102 | 103 | template ::value)> 104 | bool operator()(T) { 105 | return false; 106 | } 107 | }; 108 | 109 | template struct make_unsigned_or_bool : std::make_unsigned {}; 110 | 111 | template <> struct make_unsigned_or_bool { using type = bool; }; 112 | 113 | template class arg_converter { 114 | private: 115 | using char_type = typename Context::char_type; 116 | 117 | basic_format_arg& arg_; 118 | char_type type_; 119 | 120 | public: 121 | arg_converter(basic_format_arg& arg, char_type type) 122 | : arg_(arg), type_(type) {} 123 | 124 | void operator()(bool value) { 125 | if (type_ != 's') operator()(value); 126 | } 127 | 128 | template ::value)> 129 | void operator()(U value) { 130 | bool is_signed = type_ == 'd' || type_ == 'i'; 131 | using target_type = conditional_t::value, U, T>; 132 | if (const_check(sizeof(target_type) <= sizeof(int))) { 133 | // Extra casts are used to silence warnings. 134 | if (is_signed) { 135 | arg_ = detail::make_arg( 136 | static_cast(static_cast(value))); 137 | } else { 138 | using unsigned_type = typename make_unsigned_or_bool::type; 139 | arg_ = detail::make_arg( 140 | static_cast(static_cast(value))); 141 | } 142 | } else { 143 | if (is_signed) { 144 | // glibc's printf doesn't sign extend arguments of smaller types: 145 | // std::printf("%lld", -42); // prints "4294967254" 146 | // but we don't have to do the same because it's a UB. 147 | arg_ = detail::make_arg(static_cast(value)); 148 | } else { 149 | arg_ = detail::make_arg( 150 | static_cast::type>(value)); 151 | } 152 | } 153 | } 154 | 155 | template ::value)> 156 | void operator()(U) {} // No conversion needed for non-integral types. 157 | }; 158 | 159 | // Converts an integer argument to T for printf, if T is an integral type. 160 | // If T is void, the argument is converted to corresponding signed or unsigned 161 | // type depending on the type specifier: 'd' and 'i' - signed, other - 162 | // unsigned). 163 | template 164 | void convert_arg(basic_format_arg& arg, Char type) { 165 | visit_format_arg(arg_converter(arg, type), arg); 166 | } 167 | 168 | // Converts an integer argument to char for printf. 169 | template class char_converter { 170 | private: 171 | basic_format_arg& arg_; 172 | 173 | public: 174 | explicit char_converter(basic_format_arg& arg) : arg_(arg) {} 175 | 176 | template ::value)> 177 | void operator()(T value) { 178 | arg_ = detail::make_arg( 179 | static_cast(value)); 180 | } 181 | 182 | template ::value)> 183 | void operator()(T) {} // No conversion needed for non-integral types. 184 | }; 185 | 186 | // An argument visitor that return a pointer to a C string if argument is a 187 | // string or null otherwise. 188 | template struct get_cstring { 189 | template const Char* operator()(T) { return nullptr; } 190 | const Char* operator()(const Char* s) { return s; } 191 | }; 192 | 193 | // Checks if an argument is a valid printf width specifier and sets 194 | // left alignment if it is negative. 195 | template class printf_width_handler { 196 | private: 197 | using format_specs = basic_format_specs; 198 | 199 | format_specs& specs_; 200 | 201 | public: 202 | explicit printf_width_handler(format_specs& specs) : specs_(specs) {} 203 | 204 | template ::value)> 205 | unsigned operator()(T value) { 206 | auto width = static_cast>(value); 207 | if (detail::is_negative(value)) { 208 | specs_.align = align::left; 209 | width = 0 - width; 210 | } 211 | unsigned int_max = max_value(); 212 | if (width > int_max) FMT_THROW(format_error("number is too big")); 213 | return static_cast(width); 214 | } 215 | 216 | template ::value)> 217 | unsigned operator()(T) { 218 | FMT_THROW(format_error("width is not integer")); 219 | return 0; 220 | } 221 | }; 222 | 223 | // The ``printf`` argument formatter. 224 | template 225 | class printf_arg_formatter : public arg_formatter { 226 | private: 227 | using base = arg_formatter; 228 | using context_type = basic_printf_context; 229 | using format_specs = basic_format_specs; 230 | 231 | context_type& context_; 232 | 233 | OutputIt write_null_pointer(bool is_string = false) { 234 | auto s = this->specs; 235 | s.type = presentation_type::none; 236 | return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); 237 | } 238 | 239 | public: 240 | printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx) 241 | : base{iter, s, locale_ref()}, context_(ctx) {} 242 | 243 | OutputIt operator()(monostate value) { return base::operator()(value); } 244 | 245 | template ::value)> 246 | OutputIt operator()(T value) { 247 | // MSVC2013 fails to compile separate overloads for bool and Char so use 248 | // std::is_same instead. 249 | if (std::is_same::value) { 250 | format_specs fmt_specs = this->specs; 251 | if (fmt_specs.type != presentation_type::none && 252 | fmt_specs.type != presentation_type::chr) { 253 | return (*this)(static_cast(value)); 254 | } 255 | fmt_specs.sign = sign::none; 256 | fmt_specs.alt = false; 257 | fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. 258 | // align::numeric needs to be overwritten here since the '0' flag is 259 | // ignored for non-numeric types 260 | if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) 261 | fmt_specs.align = align::right; 262 | return write(this->out, static_cast(value), fmt_specs); 263 | } 264 | return base::operator()(value); 265 | } 266 | 267 | template ::value)> 268 | OutputIt operator()(T value) { 269 | return base::operator()(value); 270 | } 271 | 272 | /** Formats a null-terminated C string. */ 273 | OutputIt operator()(const char* value) { 274 | if (value) return base::operator()(value); 275 | return write_null_pointer(this->specs.type != presentation_type::pointer); 276 | } 277 | 278 | /** Formats a null-terminated wide C string. */ 279 | OutputIt operator()(const wchar_t* value) { 280 | if (value) return base::operator()(value); 281 | return write_null_pointer(this->specs.type != presentation_type::pointer); 282 | } 283 | 284 | OutputIt operator()(basic_string_view value) { 285 | return base::operator()(value); 286 | } 287 | 288 | /** Formats a pointer. */ 289 | OutputIt operator()(const void* value) { 290 | return value ? base::operator()(value) : write_null_pointer(); 291 | } 292 | 293 | /** Formats an argument of a custom (user-defined) type. */ 294 | OutputIt operator()(typename basic_format_arg::handle handle) { 295 | auto parse_ctx = 296 | basic_printf_parse_context(basic_string_view()); 297 | handle.format(parse_ctx, context_); 298 | return this->out; 299 | } 300 | }; 301 | 302 | template 303 | void parse_flags(basic_format_specs& specs, const Char*& it, 304 | const Char* end) { 305 | for (; it != end; ++it) { 306 | switch (*it) { 307 | case '-': 308 | specs.align = align::left; 309 | break; 310 | case '+': 311 | specs.sign = sign::plus; 312 | break; 313 | case '0': 314 | specs.fill[0] = '0'; 315 | break; 316 | case ' ': 317 | if (specs.sign != sign::plus) { 318 | specs.sign = sign::space; 319 | } 320 | break; 321 | case '#': 322 | specs.alt = true; 323 | break; 324 | default: 325 | return; 326 | } 327 | } 328 | } 329 | 330 | template 331 | int parse_header(const Char*& it, const Char* end, 332 | basic_format_specs& specs, GetArg get_arg) { 333 | int arg_index = -1; 334 | Char c = *it; 335 | if (c >= '0' && c <= '9') { 336 | // Parse an argument index (if followed by '$') or a width possibly 337 | // preceded with '0' flag(s). 338 | int value = parse_nonnegative_int(it, end, -1); 339 | if (it != end && *it == '$') { // value is an argument index 340 | ++it; 341 | arg_index = value != -1 ? value : max_value(); 342 | } else { 343 | if (c == '0') specs.fill[0] = '0'; 344 | if (value != 0) { 345 | // Nonzero value means that we parsed width and don't need to 346 | // parse it or flags again, so return now. 347 | if (value == -1) FMT_THROW(format_error("number is too big")); 348 | specs.width = value; 349 | return arg_index; 350 | } 351 | } 352 | } 353 | parse_flags(specs, it, end); 354 | // Parse width. 355 | if (it != end) { 356 | if (*it >= '0' && *it <= '9') { 357 | specs.width = parse_nonnegative_int(it, end, -1); 358 | if (specs.width == -1) FMT_THROW(format_error("number is too big")); 359 | } else if (*it == '*') { 360 | ++it; 361 | specs.width = static_cast(visit_format_arg( 362 | detail::printf_width_handler(specs), get_arg(-1))); 363 | } 364 | } 365 | return arg_index; 366 | } 367 | 368 | template 369 | void vprintf(buffer& buf, basic_string_view format, 370 | basic_format_args args) { 371 | using OutputIt = buffer_appender; 372 | auto out = OutputIt(buf); 373 | auto context = basic_printf_context(out, args); 374 | auto parse_ctx = basic_printf_parse_context(format); 375 | 376 | // Returns the argument with specified index or, if arg_index is -1, the next 377 | // argument. 378 | auto get_arg = [&](int arg_index) { 379 | if (arg_index < 0) 380 | arg_index = parse_ctx.next_arg_id(); 381 | else 382 | parse_ctx.check_arg_id(--arg_index); 383 | return detail::get_arg(context, arg_index); 384 | }; 385 | 386 | const Char* start = parse_ctx.begin(); 387 | const Char* end = parse_ctx.end(); 388 | auto it = start; 389 | while (it != end) { 390 | if (!detail::find(it, end, '%', it)) { 391 | it = end; // detail::find leaves it == nullptr if it doesn't find '%' 392 | break; 393 | } 394 | Char c = *it++; 395 | if (it != end && *it == c) { 396 | out = detail::write( 397 | out, basic_string_view(start, detail::to_unsigned(it - start))); 398 | start = ++it; 399 | continue; 400 | } 401 | out = detail::write(out, basic_string_view( 402 | start, detail::to_unsigned(it - 1 - start))); 403 | 404 | basic_format_specs specs; 405 | specs.align = align::right; 406 | 407 | // Parse argument index, flags and width. 408 | int arg_index = parse_header(it, end, specs, get_arg); 409 | if (arg_index == 0) parse_ctx.on_error("argument not found"); 410 | 411 | // Parse precision. 412 | if (it != end && *it == '.') { 413 | ++it; 414 | c = it != end ? *it : 0; 415 | if ('0' <= c && c <= '9') { 416 | specs.precision = parse_nonnegative_int(it, end, 0); 417 | } else if (c == '*') { 418 | ++it; 419 | specs.precision = static_cast( 420 | visit_format_arg(detail::printf_precision_handler(), get_arg(-1))); 421 | } else { 422 | specs.precision = 0; 423 | } 424 | } 425 | 426 | auto arg = get_arg(arg_index); 427 | // For d, i, o, u, x, and X conversion specifiers, if a precision is 428 | // specified, the '0' flag is ignored 429 | if (specs.precision >= 0 && arg.is_integral()) 430 | specs.fill[0] = 431 | ' '; // Ignore '0' flag for non-numeric types or if '-' present. 432 | if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) { 433 | auto str = visit_format_arg(detail::get_cstring(), arg); 434 | auto str_end = str + specs.precision; 435 | auto nul = std::find(str, str_end, Char()); 436 | arg = detail::make_arg>( 437 | basic_string_view( 438 | str, detail::to_unsigned(nul != str_end ? nul - str 439 | : specs.precision))); 440 | } 441 | if (specs.alt && visit_format_arg(detail::is_zero_int(), arg)) 442 | specs.alt = false; 443 | if (specs.fill[0] == '0') { 444 | if (arg.is_arithmetic() && specs.align != align::left) 445 | specs.align = align::numeric; 446 | else 447 | specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-' 448 | // flag is also present. 449 | } 450 | 451 | // Parse length and convert the argument to the required type. 452 | c = it != end ? *it++ : 0; 453 | Char t = it != end ? *it : 0; 454 | using detail::convert_arg; 455 | switch (c) { 456 | case 'h': 457 | if (t == 'h') { 458 | ++it; 459 | t = it != end ? *it : 0; 460 | convert_arg(arg, t); 461 | } else { 462 | convert_arg(arg, t); 463 | } 464 | break; 465 | case 'l': 466 | if (t == 'l') { 467 | ++it; 468 | t = it != end ? *it : 0; 469 | convert_arg(arg, t); 470 | } else { 471 | convert_arg(arg, t); 472 | } 473 | break; 474 | case 'j': 475 | convert_arg(arg, t); 476 | break; 477 | case 'z': 478 | convert_arg(arg, t); 479 | break; 480 | case 't': 481 | convert_arg(arg, t); 482 | break; 483 | case 'L': 484 | // printf produces garbage when 'L' is omitted for long double, no 485 | // need to do the same. 486 | break; 487 | default: 488 | --it; 489 | convert_arg(arg, c); 490 | } 491 | 492 | // Parse type. 493 | if (it == end) FMT_THROW(format_error("invalid format string")); 494 | char type = static_cast(*it++); 495 | if (arg.is_integral()) { 496 | // Normalize type. 497 | switch (type) { 498 | case 'i': 499 | case 'u': 500 | type = 'd'; 501 | break; 502 | case 'c': 503 | visit_format_arg( 504 | detail::char_converter>(arg), 505 | arg); 506 | break; 507 | } 508 | } 509 | specs.type = parse_presentation_type(type); 510 | if (specs.type == presentation_type::none) 511 | parse_ctx.on_error("invalid type specifier"); 512 | 513 | start = it; 514 | 515 | // Format argument. 516 | out = visit_format_arg( 517 | detail::printf_arg_formatter(out, specs, context), arg); 518 | } 519 | detail::write(out, basic_string_view(start, to_unsigned(it - start))); 520 | } 521 | FMT_END_DETAIL_NAMESPACE 522 | 523 | template 524 | using basic_printf_context_t = 525 | basic_printf_context, Char>; 526 | 527 | using printf_context = basic_printf_context_t; 528 | using wprintf_context = basic_printf_context_t; 529 | 530 | using printf_args = basic_format_args; 531 | using wprintf_args = basic_format_args; 532 | 533 | /** 534 | \rst 535 | Constructs an `~fmt::format_arg_store` object that contains references to 536 | arguments and can be implicitly converted to `~fmt::printf_args`. 537 | \endrst 538 | */ 539 | template 540 | inline auto make_printf_args(const T&... args) 541 | -> format_arg_store { 542 | return {args...}; 543 | } 544 | 545 | /** 546 | \rst 547 | Constructs an `~fmt::format_arg_store` object that contains references to 548 | arguments and can be implicitly converted to `~fmt::wprintf_args`. 549 | \endrst 550 | */ 551 | template 552 | inline auto make_wprintf_args(const T&... args) 553 | -> format_arg_store { 554 | return {args...}; 555 | } 556 | 557 | template > 558 | inline auto vsprintf( 559 | const S& fmt, 560 | basic_format_args>> args) 561 | -> std::basic_string { 562 | basic_memory_buffer buffer; 563 | vprintf(buffer, detail::to_string_view(fmt), args); 564 | return to_string(buffer); 565 | } 566 | 567 | /** 568 | \rst 569 | Formats arguments and returns the result as a string. 570 | 571 | **Example**:: 572 | 573 | std::string message = fmt::sprintf("The answer is %d", 42); 574 | \endrst 575 | */ 576 | template ::value, char_t>> 578 | inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { 579 | using context = basic_printf_context_t; 580 | return vsprintf(detail::to_string_view(fmt), 581 | fmt::make_format_args(args...)); 582 | } 583 | 584 | template > 585 | inline auto vfprintf( 586 | std::FILE* f, const S& fmt, 587 | basic_format_args>> args) 588 | -> int { 589 | basic_memory_buffer buffer; 590 | vprintf(buffer, detail::to_string_view(fmt), args); 591 | size_t size = buffer.size(); 592 | return std::fwrite(buffer.data(), sizeof(Char), size, f) < size 593 | ? -1 594 | : static_cast(size); 595 | } 596 | 597 | /** 598 | \rst 599 | Prints formatted data to the file *f*. 600 | 601 | **Example**:: 602 | 603 | fmt::fprintf(stderr, "Don't %s!", "panic"); 604 | \endrst 605 | */ 606 | template > 607 | inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { 608 | using context = basic_printf_context_t; 609 | return vfprintf(f, detail::to_string_view(fmt), 610 | fmt::make_format_args(args...)); 611 | } 612 | 613 | template > 614 | inline auto vprintf( 615 | const S& fmt, 616 | basic_format_args>> args) 617 | -> int { 618 | return vfprintf(stdout, detail::to_string_view(fmt), args); 619 | } 620 | 621 | /** 622 | \rst 623 | Prints formatted data to ``stdout``. 624 | 625 | **Example**:: 626 | 627 | fmt::printf("Elapsed time: %.2f seconds", 1.23); 628 | \endrst 629 | */ 630 | template ::value)> 631 | inline auto printf(const S& fmt, const T&... args) -> int { 632 | return vprintf( 633 | detail::to_string_view(fmt), 634 | fmt::make_format_args>>(args...)); 635 | } 636 | 637 | FMT_MODULE_EXPORT_END 638 | FMT_END_NAMESPACE 639 | 640 | #endif // FMT_PRINTF_H_ 641 | -------------------------------------------------------------------------------- /src/fmt/std.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - formatters for standard library types 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_STD_H_ 9 | #define FMT_STD_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "ostream.h" 16 | 17 | #if FMT_HAS_INCLUDE() 18 | # include 19 | #endif 20 | // Checking FMT_CPLUSPLUS for warning suppression in MSVC. 21 | #if FMT_CPLUSPLUS >= 201703L 22 | # if FMT_HAS_INCLUDE() 23 | # include 24 | # endif 25 | # if FMT_HAS_INCLUDE() 26 | # include 27 | # endif 28 | #endif 29 | 30 | #ifdef __cpp_lib_filesystem 31 | FMT_BEGIN_NAMESPACE 32 | 33 | namespace detail { 34 | 35 | template 36 | void write_escaped_path(basic_memory_buffer& quoted, 37 | const std::filesystem::path& p) { 38 | write_escaped_string(std::back_inserter(quoted), p.string()); 39 | } 40 | # ifdef _WIN32 41 | template <> 42 | inline void write_escaped_path(basic_memory_buffer& quoted, 43 | const std::filesystem::path& p) { 44 | auto s = p.u8string(); 45 | write_escaped_string( 46 | std::back_inserter(quoted), 47 | string_view(reinterpret_cast(s.c_str()), s.size())); 48 | } 49 | # endif 50 | template <> 51 | inline void write_escaped_path( 52 | basic_memory_buffer& quoted, 53 | const std::filesystem::path& p) { 54 | write_escaped_string( 55 | std::back_inserter(quoted), p.native()); 56 | } 57 | 58 | } // namespace detail 59 | 60 | template 61 | struct formatter 62 | : formatter> { 63 | template 64 | auto format(const std::filesystem::path& p, FormatContext& ctx) const -> 65 | typename FormatContext::iterator { 66 | basic_memory_buffer quoted; 67 | detail::write_escaped_path(quoted, p); 68 | return formatter>::format( 69 | basic_string_view(quoted.data(), quoted.size()), ctx); 70 | } 71 | }; 72 | FMT_END_NAMESPACE 73 | #endif 74 | 75 | FMT_BEGIN_NAMESPACE 76 | template 77 | struct formatter : basic_ostream_formatter {}; 78 | FMT_END_NAMESPACE 79 | 80 | #ifdef __cpp_lib_variant 81 | FMT_BEGIN_NAMESPACE 82 | template struct formatter { 83 | template 84 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 85 | return ctx.begin(); 86 | } 87 | 88 | template 89 | auto format(const std::monostate&, FormatContext& ctx) const 90 | -> decltype(ctx.out()) { 91 | auto out = ctx.out(); 92 | out = detail::write(out, "monostate"); 93 | return out; 94 | } 95 | }; 96 | 97 | namespace detail { 98 | 99 | template 100 | using variant_index_sequence = 101 | std::make_index_sequence::value>; 102 | 103 | // variant_size and variant_alternative check. 104 | template 105 | struct is_variant_like_ : std::false_type {}; 106 | template 107 | struct is_variant_like_::value)>> 108 | : std::true_type {}; 109 | 110 | // formattable element check 111 | template class is_variant_formattable_ { 112 | template 113 | static std::conjunction< 114 | is_formattable, C>...> 115 | check(std::index_sequence); 116 | 117 | public: 118 | static constexpr const bool value = 119 | decltype(check(variant_index_sequence{}))::value; 120 | }; 121 | 122 | template 123 | auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { 124 | if constexpr (is_string::value) 125 | return write_escaped_string(out, detail::to_string_view(v)); 126 | else if constexpr (std::is_same_v) 127 | return write_escaped_char(out, v); 128 | else 129 | return write(out, v); 130 | } 131 | 132 | } // namespace detail 133 | 134 | template struct is_variant_like { 135 | static constexpr const bool value = detail::is_variant_like_::value; 136 | }; 137 | 138 | template struct is_variant_formattable { 139 | static constexpr const bool value = 140 | detail::is_variant_formattable_::value; 141 | }; 142 | 143 | template 144 | struct formatter< 145 | Variant, Char, 146 | std::enable_if_t, is_variant_formattable>>> { 148 | template 149 | FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { 150 | return ctx.begin(); 151 | } 152 | 153 | template 154 | auto format(const Variant& value, FormatContext& ctx) const 155 | -> decltype(ctx.out()) { 156 | auto out = ctx.out(); 157 | 158 | out = detail::write(out, "variant("); 159 | std::visit( 160 | [&](const auto& v) { 161 | out = detail::write_variant_alternative(out, v); 162 | }, 163 | value); 164 | *out++ = ')'; 165 | return out; 166 | } 167 | }; 168 | FMT_END_NAMESPACE 169 | #endif 170 | 171 | #endif // FMT_STD_H_ 172 | -------------------------------------------------------------------------------- /src/fmt/xchar.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - optional wchar_t and exotic character support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_XCHAR_H_ 9 | #define FMT_XCHAR_H_ 10 | 11 | #include 12 | 13 | #include "format.h" 14 | 15 | FMT_BEGIN_NAMESPACE 16 | namespace detail { 17 | template 18 | using is_exotic_char = bool_constant::value>; 19 | } 20 | 21 | FMT_MODULE_EXPORT_BEGIN 22 | 23 | using wstring_view = basic_string_view; 24 | using wformat_parse_context = basic_format_parse_context; 25 | using wformat_context = buffer_context; 26 | using wformat_args = basic_format_args; 27 | using wmemory_buffer = basic_memory_buffer; 28 | 29 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 30 | // Workaround broken conversion on older gcc. 31 | template using wformat_string = wstring_view; 32 | inline auto runtime(wstring_view s) -> wstring_view { return s; } 33 | #else 34 | template 35 | using wformat_string = basic_format_string...>; 36 | inline auto runtime(wstring_view s) -> basic_runtime { return {{s}}; } 37 | #endif 38 | 39 | template <> struct is_char : std::true_type {}; 40 | template <> struct is_char : std::true_type {}; 41 | template <> struct is_char : std::true_type {}; 42 | template <> struct is_char : std::true_type {}; 43 | 44 | template 45 | constexpr format_arg_store make_wformat_args( 46 | const Args&... args) { 47 | return {args...}; 48 | } 49 | 50 | inline namespace literals { 51 | #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS 52 | constexpr detail::udl_arg operator"" _a(const wchar_t* s, size_t) { 53 | return {s}; 54 | } 55 | #endif 56 | } // namespace literals 57 | 58 | template 59 | auto join(It begin, Sentinel end, wstring_view sep) 60 | -> join_view { 61 | return {begin, end, sep}; 62 | } 63 | 64 | template 65 | auto join(Range&& range, wstring_view sep) 66 | -> join_view, detail::sentinel_t, 67 | wchar_t> { 68 | return join(std::begin(range), std::end(range), sep); 69 | } 70 | 71 | template 72 | auto join(std::initializer_list list, wstring_view sep) 73 | -> join_view { 74 | return join(std::begin(list), std::end(list), sep); 75 | } 76 | 77 | template ::value)> 78 | auto vformat(basic_string_view format_str, 79 | basic_format_args>> args) 80 | -> std::basic_string { 81 | basic_memory_buffer buffer; 82 | detail::vformat_to(buffer, format_str, args); 83 | return to_string(buffer); 84 | } 85 | 86 | template 87 | auto format(wformat_string fmt, T&&... args) -> std::wstring { 88 | return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); 89 | } 90 | 91 | // Pass char_t as a default template parameter instead of using 92 | // std::basic_string> to reduce the symbol size. 93 | template , 94 | FMT_ENABLE_IF(!std::is_same::value && 95 | !std::is_same::value)> 96 | auto format(const S& format_str, Args&&... args) -> std::basic_string { 97 | return vformat(detail::to_string_view(format_str), 98 | fmt::make_format_args>(args...)); 99 | } 100 | 101 | template , 102 | FMT_ENABLE_IF(detail::is_locale::value&& 103 | detail::is_exotic_char::value)> 104 | inline auto vformat( 105 | const Locale& loc, const S& format_str, 106 | basic_format_args>> args) 107 | -> std::basic_string { 108 | return detail::vformat(loc, detail::to_string_view(format_str), args); 109 | } 110 | 111 | template , 113 | FMT_ENABLE_IF(detail::is_locale::value&& 114 | detail::is_exotic_char::value)> 115 | inline auto format(const Locale& loc, const S& format_str, Args&&... args) 116 | -> std::basic_string { 117 | return detail::vformat(loc, detail::to_string_view(format_str), 118 | fmt::make_format_args>(args...)); 119 | } 120 | 121 | template , 122 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 123 | detail::is_exotic_char::value)> 124 | auto vformat_to(OutputIt out, const S& format_str, 125 | basic_format_args>> args) 126 | -> OutputIt { 127 | auto&& buf = detail::get_buffer(out); 128 | detail::vformat_to(buf, detail::to_string_view(format_str), args); 129 | return detail::get_iterator(buf); 130 | } 131 | 132 | template , 134 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 135 | detail::is_exotic_char::value)> 136 | inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { 137 | return vformat_to(out, detail::to_string_view(fmt), 138 | fmt::make_format_args>(args...)); 139 | } 140 | 141 | template , 143 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 144 | detail::is_locale::value&& 145 | detail::is_exotic_char::value)> 146 | inline auto vformat_to( 147 | OutputIt out, const Locale& loc, const S& format_str, 148 | basic_format_args>> args) -> OutputIt { 149 | auto&& buf = detail::get_buffer(out); 150 | vformat_to(buf, detail::to_string_view(format_str), args, 151 | detail::locale_ref(loc)); 152 | return detail::get_iterator(buf); 153 | } 154 | 155 | template < 156 | typename OutputIt, typename Locale, typename S, typename... Args, 157 | typename Char = char_t, 158 | bool enable = detail::is_output_iterator::value&& 159 | detail::is_locale::value&& detail::is_exotic_char::value> 160 | inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, 161 | Args&&... args) -> 162 | typename std::enable_if::type { 163 | return vformat_to(out, loc, to_string_view(format_str), 164 | fmt::make_format_args>(args...)); 165 | } 166 | 167 | template ::value&& 169 | detail::is_exotic_char::value)> 170 | inline auto vformat_to_n( 171 | OutputIt out, size_t n, basic_string_view format_str, 172 | basic_format_args>> args) 173 | -> format_to_n_result { 174 | detail::iterator_buffer buf(out, 175 | n); 176 | detail::vformat_to(buf, format_str, args); 177 | return {buf.out(), buf.count()}; 178 | } 179 | 180 | template , 182 | FMT_ENABLE_IF(detail::is_output_iterator::value&& 183 | detail::is_exotic_char::value)> 184 | inline auto format_to_n(OutputIt out, size_t n, const S& fmt, 185 | const Args&... args) -> format_to_n_result { 186 | return vformat_to_n(out, n, detail::to_string_view(fmt), 187 | fmt::make_format_args>(args...)); 188 | } 189 | 190 | template , 191 | FMT_ENABLE_IF(detail::is_exotic_char::value)> 192 | inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { 193 | detail::counting_buffer buf; 194 | detail::vformat_to(buf, detail::to_string_view(fmt), 195 | fmt::make_format_args>(args...)); 196 | return buf.count(); 197 | } 198 | 199 | inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { 200 | wmemory_buffer buffer; 201 | detail::vformat_to(buffer, fmt, args); 202 | buffer.push_back(L'\0'); 203 | if (std::fputws(buffer.data(), f) == -1) 204 | FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 205 | } 206 | 207 | inline void vprint(wstring_view fmt, wformat_args args) { 208 | vprint(stdout, fmt, args); 209 | } 210 | 211 | template 212 | void print(std::FILE* f, wformat_string fmt, T&&... args) { 213 | return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); 214 | } 215 | 216 | template void print(wformat_string fmt, T&&... args) { 217 | return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); 218 | } 219 | 220 | /** 221 | Converts *value* to ``std::wstring`` using the default format for type *T*. 222 | */ 223 | template inline auto to_wstring(const T& value) -> std::wstring { 224 | return format(FMT_STRING(L"{}"), value); 225 | } 226 | FMT_MODULE_EXPORT_END 227 | FMT_END_NAMESPACE 228 | 229 | #endif // FMT_XCHAR_H_ 230 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nexquery/samp-textdraw-streamer/f27b79a38ada8120527e2ec4bc63c6c53c4dbf80/src/main.cpp -------------------------------------------------------------------------------- /src/natives.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "sampgdk.hpp" 20 | 21 | #define CHECK_PARAMS(n) \ 22 | if (params[0] != (n * 4)) \ 23 | { \ 24 | sampgdk::logprintf("%s: Expecting %d parameter(s), but found %d.", __func__, n, params[0] / sizeof(cell)); \ 25 | return 0; \ 26 | } 27 | 28 | namespace Natives 29 | { 30 | // Global TextDraw 31 | cell AMX_NATIVE_CALL CreateDynamicTextDraw(AMX* amx, cell* params); 32 | cell AMX_NATIVE_CALL DestroyDynamicTextDraw(AMX* amx, cell* params); 33 | cell AMX_NATIVE_CALL DynamicTextDrawLetterSize(AMX* amx, cell* params); 34 | cell AMX_NATIVE_CALL DynamicTextDrawTextSize(AMX* amx, cell* params); 35 | cell AMX_NATIVE_CALL DynamicTextDrawAlignment(AMX* amx, cell* params); 36 | cell AMX_NATIVE_CALL DynamicTextDrawColour(AMX* amx, cell* params); 37 | cell AMX_NATIVE_CALL DynamicTextDrawUseBox(AMX* amx, cell* params); 38 | cell AMX_NATIVE_CALL DynamicTextDrawBoxColour(AMX* amx, cell* params); 39 | cell AMX_NATIVE_CALL DynamicTextDrawSetShadow(AMX* amx, cell* params); 40 | cell AMX_NATIVE_CALL DynamicTextDrawSetOutline(AMX* amx, cell* params); 41 | cell AMX_NATIVE_CALL DynamicTextDrawBackgroundColour(AMX* amx, cell* params); 42 | cell AMX_NATIVE_CALL DynamicTextDrawFont(AMX* amx, cell* params); 43 | cell AMX_NATIVE_CALL DynamicTextDrawSetProportional(AMX* amx, cell* params); 44 | cell AMX_NATIVE_CALL DynamicTextDrawSetSelectable(AMX* amx, cell* params); 45 | cell AMX_NATIVE_CALL DynamicTextDrawShowForPlayer(AMX* amx, cell* params); 46 | cell AMX_NATIVE_CALL DynamicTextDrawHideForPlayer(AMX* amx, cell* params); 47 | cell AMX_NATIVE_CALL DynamicTextDrawShowForAll(AMX* amx, cell* params); 48 | cell AMX_NATIVE_CALL DynamicTextDrawHideForAll(AMX* amx, cell* params); 49 | cell AMX_NATIVE_CALL DynamicTextDrawSetString(AMX* amx, cell* params); 50 | cell AMX_NATIVE_CALL DynamicTextDrawSetPreviewModel(AMX* amx, cell* params); 51 | cell AMX_NATIVE_CALL DynamicTextDrawSetPreviewRot(AMX* amx, cell* params); 52 | cell AMX_NATIVE_CALL DynamicTextDrawSetPreviewVehicleColours(AMX* amx, cell* params); 53 | cell AMX_NATIVE_CALL IsValidDynamicTextDraw(AMX* amx, cell* params); 54 | cell AMX_NATIVE_CALL IsDynamicTextDrawVisibleForPlayer(AMX* amx, cell* params); 55 | cell AMX_NATIVE_CALL DynamicTextDrawGetString(AMX* amx, cell* params); 56 | cell AMX_NATIVE_CALL DynamicTextDrawSetPos(AMX* amx, cell* params); 57 | cell AMX_NATIVE_CALL DynamicTextDrawGetLetterSize(AMX* amx, cell* params); 58 | cell AMX_NATIVE_CALL DynamicTextDrawGetTextSize(AMX* amx, cell* params); 59 | cell AMX_NATIVE_CALL DynamicTextDrawGetPos(AMX* amx, cell* params); 60 | cell AMX_NATIVE_CALL DynamicTextDrawGetColour(AMX* amx, cell* params); 61 | cell AMX_NATIVE_CALL DynamicTextDrawGetBoxColour(AMX* amx, cell* params); 62 | cell AMX_NATIVE_CALL DynamicTextDrawGetBackgroundColour(AMX* amx, cell* params); 63 | cell AMX_NATIVE_CALL DynamicTextDrawGetShadow(AMX* amx, cell* params); 64 | cell AMX_NATIVE_CALL DynamicTextDrawGetOutline(AMX* amx, cell* params); 65 | cell AMX_NATIVE_CALL DynamicTextDrawGetFont(AMX* amx, cell* params); 66 | cell AMX_NATIVE_CALL DynamicTextDrawIsBox(AMX* amx, cell* params); 67 | cell AMX_NATIVE_CALL DynamicTextDrawIsProportional(AMX* amx, cell* params); 68 | cell AMX_NATIVE_CALL DynamicTextDrawIsSelectable(AMX* amx, cell* params); 69 | cell AMX_NATIVE_CALL DynamicTextDrawGetAlignment(AMX* amx, cell* params); 70 | cell AMX_NATIVE_CALL DynamicTextDrawGetPreviewModel(AMX* amx, cell* params); 71 | cell AMX_NATIVE_CALL DynamicTextDrawGetPreviewRot(AMX* amx, cell* params); 72 | cell AMX_NATIVE_CALL DynamicTextDrawGetPreviewVehicleColours(AMX* amx, cell* params); 73 | cell AMX_NATIVE_CALL DynamicTextDrawGetRealID(AMX* amx, cell* params); 74 | cell AMX_NATIVE_CALL DynamicTextDrawGetSize(AMX* amx, cell* params); 75 | 76 | // Player TextDraw 77 | cell AMX_NATIVE_CALL CreateDynamicPlayerTextDraw(AMX* amx, cell* params); 78 | cell AMX_NATIVE_CALL DestroyDynamicPlayerTextDraw(AMX* amx, cell* params); 79 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawLetterSize(AMX* amx, cell* params); 80 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawTextSize(AMX* amx, cell* params); 81 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawAlignment(AMX* amx, cell* params); 82 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawColour(AMX* amx, cell* params); 83 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawUseBox(AMX* amx, cell* params); 84 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawBoxColor(AMX* amx, cell* params); 85 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetShadow(AMX* amx, cell* params); 86 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetOutline(AMX* amx, cell* params); 87 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawBackgroundColour(AMX* amx, cell* params); 88 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawFont(AMX* amx, cell* params); 89 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetProportional(AMX* amx, cell* params); 90 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetSelectable(AMX* amx, cell* params); 91 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawShow(AMX* amx, cell* params); 92 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawHide(AMX* amx, cell* params); 93 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetString(AMX* amx, cell* params); 94 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetPreviewModel(AMX* amx, cell* params); 95 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetPreviewRot(AMX* amx, cell* params); 96 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetPreviewVehicleColours(AMX* amx, cell* params); 97 | cell AMX_NATIVE_CALL IsValidDynamicPlayerTextDraw(AMX* amx, cell* params); 98 | cell AMX_NATIVE_CALL IsDynamicPlayerTextDrawVisible(AMX* amx, cell* params); 99 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetString(AMX* amx, cell* params); 100 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawSetPos(AMX* amx, cell* params); 101 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetLetterSize(AMX* amx, cell* params); 102 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetTextSize(AMX* amx, cell* params); 103 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetPos(AMX* amx, cell* params); 104 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetColour(AMX* amx, cell* params); 105 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetBoxColour(AMX* amx, cell* params); 106 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetBackgroundColour(AMX* amx, cell* params); 107 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetShadow(AMX* amx, cell* params); 108 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetOutline(AMX* amx, cell* params); 109 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetFont(AMX* amx, cell* params); 110 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawIsBox(AMX* amx, cell* params); 111 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawIsProportional(AMX* amx, cell* params); 112 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawIsSelectable(AMX* amx, cell* params); 113 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetAlignment(AMX* amx, cell* params); 114 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetPreviewModel(AMX* amx, cell* params); 115 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetPreviewRot(AMX* amx, cell* params); 116 | cell AMX_NATIVE_CALL DynamicPlayerTextDrawGetPreviewVehicleColours(AMX* amx, cell* params); 117 | cell AMX_NATIVE_CALL PlayerTextDrawGetRealID(AMX* amx, cell* params); 118 | cell AMX_NATIVE_CALL PlayerTextDrawGetSize(AMX* amx, cell* params); 119 | 120 | // Data (Int) 121 | cell AMX_NATIVE_CALL DynamicTextDraw_SetIntData(AMX* amx, cell* params); 122 | cell AMX_NATIVE_CALL DynamicTextDraw_GetIntData(AMX* amx, cell* params); 123 | cell AMX_NATIVE_CALL DynamicTextDraw_ClearIntData(AMX* amx, cell* params); 124 | 125 | // Data (Float) 126 | cell AMX_NATIVE_CALL DynamicTextDraw_SetFloatData(AMX* amx, cell* params); 127 | cell AMX_NATIVE_CALL DynamicTextDraw_GetFloatData(AMX* amx, cell* params); 128 | 129 | // Data (Array) 130 | cell AMX_NATIVE_CALL DynamicTextDraw_SetArrayData(AMX* amx, cell* params); 131 | cell AMX_NATIVE_CALL DynamicTextDraw_GetArrayData(AMX* amx, cell* params); 132 | cell AMX_NATIVE_CALL DynamicTextDraw_ClearArrayData(AMX* amx, cell* params); 133 | 134 | // Logger 135 | cell AMX_NATIVE_CALL TDLogger(AMX* amx, cell* params); 136 | }; -------------------------------------------------------------------------------- /src/natives_data.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "textdraw_data.hpp" 18 | #include "natives.hpp" 19 | #include "service.hpp" 20 | 21 | // 22 | // native DynamicTextDraw_SetIntData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, index, value, playerid = -1); 23 | // 24 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_SetIntData(AMX* amx, cell* params) 25 | { 26 | CHECK_PARAMS(5); 27 | 28 | int 29 | type = params[1], 30 | textid = params[2], 31 | index = params[3], 32 | value = params[4], 33 | playerid = params[5]; 34 | 35 | if (type == TDStreamer_Type::GLOBAL) 36 | { 37 | auto it = GlobalText::gText->find(textid); 38 | if (it == GlobalText::gText->end()) 39 | { 40 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 41 | return 0; 42 | } 43 | 44 | std::map* address = it->second->extra_id; 45 | (*address)[index] = value; 46 | return 1; 47 | } 48 | else if (type == TDStreamer_Type::PLAYER) 49 | { 50 | if (playerid >= 0 && playerid < MAX_PLAYERS) 51 | { 52 | auto it = PlayerText::pText[playerid]->find(textid); 53 | if (it == PlayerText::pText[playerid]->end()) 54 | { 55 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 56 | return 0; 57 | } 58 | 59 | std::map* address = it->second->extra_id; 60 | (*address)[index] = value; 61 | return 1; 62 | } 63 | } 64 | else 65 | { 66 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 67 | } 68 | 69 | return 0; 70 | } 71 | 72 | // 73 | // native DynamicTextDraw_GetIntData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, index, playerid = -1); 74 | // 75 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_GetIntData(AMX* amx, cell* params) 76 | { 77 | CHECK_PARAMS(4); 78 | 79 | int 80 | type = params[1], 81 | textid = params[2], 82 | index = params[3], 83 | playerid = params[4]; 84 | 85 | if (type == TDStreamer_Type::GLOBAL) 86 | { 87 | auto it = GlobalText::gText->find(textid); 88 | if (it == GlobalText::gText->end()) 89 | { 90 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 91 | return 0; 92 | } 93 | 94 | std::map* address = (std::map*)it->second->extra_id; 95 | return (*address)[index]; 96 | } 97 | else if (type == TDStreamer_Type::PLAYER) 98 | { 99 | if (playerid >= 0 && playerid < MAX_PLAYERS) 100 | { 101 | auto it = PlayerText::pText[playerid]->find(textid); 102 | if (it == PlayerText::pText[playerid]->end()) 103 | { 104 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 105 | return 0; 106 | } 107 | 108 | std::map* address = it->second->extra_id; 109 | return (*address)[index]; 110 | } 111 | } 112 | else 113 | { 114 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 115 | } 116 | 117 | return 0; 118 | } 119 | 120 | // 121 | // native DynamicTextDraw_ClearIntData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, playerid = -1); 122 | // 123 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_ClearIntData(AMX* amx, cell* params) 124 | { 125 | CHECK_PARAMS(3); 126 | 127 | int 128 | type = params[1], 129 | textid = params[2], 130 | playerid = params[3]; 131 | 132 | if (type == TDStreamer_Type::GLOBAL) 133 | { 134 | auto it = GlobalText::gText->find(textid); 135 | if (it == GlobalText::gText->end()) 136 | { 137 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 138 | return 0; 139 | } 140 | 141 | delete it->second->extra_id; 142 | std::map* address = new std::map(); 143 | it->second->extra_id = address; 144 | return 1; 145 | } 146 | else if (type == TDStreamer_Type::PLAYER) 147 | { 148 | if (playerid >= 0 && playerid < MAX_PLAYERS) 149 | { 150 | auto it = PlayerText::pText[playerid]->find(textid); 151 | if (it == PlayerText::pText[playerid]->end()) 152 | { 153 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 154 | return 0; 155 | } 156 | 157 | delete it->second->extra_id; 158 | std::map* address = new std::map(); 159 | it->second->extra_id = address; 160 | return 1; 161 | } 162 | } 163 | else 164 | { 165 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | // 172 | // native DynamicTextDraw_SetFloatData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, Float:value, playerid = -1); 173 | // 174 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_SetFloatData(AMX* amx, cell* params) 175 | { 176 | CHECK_PARAMS(4); 177 | 178 | int type = params[1]; 179 | int textid = params[2]; 180 | float value = amx_ctof(params[3]); 181 | int playerid = params[4]; 182 | 183 | if (type == TDStreamer_Type::GLOBAL) 184 | { 185 | auto it = GlobalText::gText->find(textid); 186 | if (it == GlobalText::gText->end()) 187 | { 188 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 189 | return 0; 190 | } 191 | 192 | it->second->float_data = value; 193 | return 1; 194 | } 195 | else if (type == TDStreamer_Type::PLAYER) 196 | { 197 | if (playerid >= 0 && playerid < MAX_PLAYERS) 198 | { 199 | auto it = PlayerText::pText[playerid]->find(textid); 200 | if (it == PlayerText::pText[playerid]->end()) 201 | { 202 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 203 | return 0; 204 | } 205 | 206 | it->second->float_data = value; 207 | return 1; 208 | } 209 | } 210 | else 211 | { 212 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 213 | } 214 | 215 | return 0; 216 | } 217 | 218 | // 219 | // native Float:DynamicTextDraw_GetFloatData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, playerid = -1); 220 | // 221 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_GetFloatData(AMX* amx, cell* params) 222 | { 223 | CHECK_PARAMS(3); 224 | 225 | int type = params[1]; 226 | int textid = params[2]; 227 | int playerid = params[3]; 228 | float value = 0.0; 229 | 230 | if (type == TDStreamer_Type::GLOBAL) 231 | { 232 | auto it = GlobalText::gText->find(textid); 233 | if (it == GlobalText::gText->end()) 234 | { 235 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 236 | return amx_ftoc(value); 237 | } 238 | return amx_ftoc(it->second->float_data); 239 | } 240 | else if (type == TDStreamer_Type::PLAYER) 241 | { 242 | if (playerid >= 0 && playerid < MAX_PLAYERS) 243 | { 244 | auto it = PlayerText::pText[playerid]->find(textid); 245 | if (it == PlayerText::pText[playerid]->end()) 246 | { 247 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 248 | return amx_ftoc(value); 249 | } 250 | return amx_ftoc(it->second->float_data); 251 | } 252 | } 253 | else 254 | { 255 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 256 | } 257 | return amx_ftoc(value); 258 | } 259 | 260 | // 261 | // native DynamicTextDraw_SetArrayData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, const src[], playerid = -1, maxSrc = sizeof(src)); 262 | // 263 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_SetArrayData(AMX* amx, cell* params) 264 | { 265 | CHECK_PARAMS(5); 266 | 267 | int type = params[1]; 268 | int textid = params[2]; 269 | int playerid = params[4]; 270 | 271 | if (type == TDStreamer_Type::GLOBAL) 272 | { 273 | auto it = GlobalText::gText->find(textid); 274 | if (it == GlobalText::gText->end()) 275 | { 276 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 277 | return 0; 278 | } 279 | 280 | it->second->array_data->clear(); 281 | 282 | cell* array = NULL; 283 | amx_GetAddr(amx, params[3], &array); 284 | for (int i = 0, j = static_cast(params[5]); i != j; ++i) 285 | { 286 | it->second->array_data->push_back(static_cast(array[i])); 287 | } 288 | return 1; 289 | } 290 | else if (type == TDStreamer_Type::PLAYER) 291 | { 292 | if (playerid >= 0 && playerid < MAX_PLAYERS) 293 | { 294 | auto it = PlayerText::pText[playerid]->find(textid); 295 | if (it == PlayerText::pText[playerid]->end()) 296 | { 297 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 298 | return 0; 299 | } 300 | 301 | it->second->array_data->clear(); 302 | 303 | cell* array = NULL; 304 | amx_GetAddr(amx, params[3], &array); 305 | for (int i = 0, j = static_cast(params[5]); i != j; ++i) 306 | { 307 | it->second->array_data->push_back(static_cast(array[i])); 308 | } 309 | return 1; 310 | } 311 | } 312 | else 313 | { 314 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 315 | } 316 | return 0; 317 | } 318 | 319 | // 320 | // native DynamicTextDraw_GetArrayData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, const dest[], playerid = -1, maxDest = sizeof(dest)); 321 | // 322 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_GetArrayData(AMX* amx, cell* params) 323 | { 324 | CHECK_PARAMS(5); 325 | 326 | int type = params[1]; 327 | int textid = params[2]; 328 | int playerid = params[4]; 329 | 330 | if (type == TDStreamer_Type::GLOBAL) 331 | { 332 | auto it = GlobalText::gText->find(textid); 333 | if (it == GlobalText::gText->end()) 334 | { 335 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 336 | return 0; 337 | } 338 | 339 | int index = 0; 340 | cell* array = NULL; 341 | amx_GetAddr(amx, params[3], &array); 342 | 343 | for (std::vector::const_iterator data = it->second->array_data->begin(); data != it->second->array_data->end(); ++data) 344 | { 345 | if (index == static_cast(params[5])) 346 | { 347 | break; 348 | } 349 | array[index++] = static_cast(*data); 350 | } 351 | return 1; 352 | } 353 | else if (type == TDStreamer_Type::PLAYER) 354 | { 355 | if (playerid >= 0 && playerid < MAX_PLAYERS) 356 | { 357 | auto it = PlayerText::pText[playerid]->find(textid); 358 | if (it == PlayerText::pText[playerid]->end()) 359 | { 360 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 361 | return 0; 362 | } 363 | 364 | int index = 0; 365 | cell* array = NULL; 366 | amx_GetAddr(amx, params[3], &array); 367 | 368 | for (std::vector::const_iterator data = it->second->array_data->begin(); data != it->second->array_data->end(); ++data) 369 | { 370 | if (index == static_cast(params[5])) 371 | { 372 | break; 373 | } 374 | array[index++] = static_cast(*data); 375 | } 376 | return 1; 377 | } 378 | } 379 | else 380 | { 381 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 382 | } 383 | return 0; 384 | } 385 | 386 | // 387 | // native DynamicTextDraw_ClearArrayData(DYNAMIC_TEXTDRAW_TYPE:type, {Text, PlayerText}:textid, playerid = -1); 388 | // 389 | cell AMX_NATIVE_CALL Natives::DynamicTextDraw_ClearArrayData(AMX* amx, cell* params) 390 | { 391 | CHECK_PARAMS(3); 392 | 393 | int type = params[1]; 394 | int textid = params[2]; 395 | int playerid = params[3]; 396 | 397 | if (type == TDStreamer_Type::GLOBAL) 398 | { 399 | auto it = GlobalText::gText->find(textid); 400 | if (it == GlobalText::gText->end()) 401 | { 402 | Plugin_Settings::ILogger(LogType::FIND_GLOBAL_TEXT, __func__, INVALID_PLAYER_ID, textid); 403 | return 0; 404 | } 405 | 406 | delete it->second->array_data; 407 | std::vector* arr = new std::vector(); 408 | it->second->array_data = arr; 409 | return 1; 410 | } 411 | else if (type == TDStreamer_Type::PLAYER) 412 | { 413 | if (playerid >= 0 && playerid < MAX_PLAYERS) 414 | { 415 | auto it = PlayerText::pText[playerid]->find(textid); 416 | if (it == PlayerText::pText[playerid]->end()) 417 | { 418 | Plugin_Settings::ILogger(LogType::FIND_PLAYER_TEXT, __func__, playerid, textid); 419 | return 0; 420 | } 421 | 422 | delete it->second->array_data; 423 | std::vector* arr = new std::vector(); 424 | it->second->array_data = arr; 425 | return 1; 426 | } 427 | } 428 | else 429 | { 430 | Plugin_Settings::ILogger(LogType::INVALID_TYPE, __func__, INVALID_PLAYER_ID, INVALID_PLAYER_ID); 431 | } 432 | return 0; 433 | } -------------------------------------------------------------------------------- /src/natives_global.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nexquery/samp-textdraw-streamer/f27b79a38ada8120527e2ec4bc63c6c53c4dbf80/src/natives_global.cpp -------------------------------------------------------------------------------- /src/natives_plugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "textdraw_data.hpp" 18 | #include "natives.hpp" 19 | #include "service.hpp" 20 | 21 | bool Plugin_Settings::logMode = true; 22 | std::string Plugin_Settings::file = "unknown"; 23 | int Plugin_Settings::line; 24 | 25 | cell AMX_NATIVE_CALL Natives::TDLogger(AMX* amx, cell* params) 26 | { 27 | CHECK_PARAMS(2); 28 | Plugin_Settings::file = service::getString(amx, params[1]); 29 | Plugin_Settings::line = static_cast(params[2]); 30 | return 1; 31 | } 32 | 33 | void Plugin_Settings::ILogger(LogType type, std::string funcs, int playerid, int textid) 34 | { 35 | if (Plugin_Settings::logMode == true) 36 | { 37 | if (type == LogType::CREATE_PLAYER_TEXTDRAW) 38 | { 39 | sampgdk::logprintf("[textdraw.streamer] %s: First use the CreatePlayerTextDraw function. (playerid: %d, textId: %d) (%s:%d)" 40 | , 41 | funcs.c_str(), 42 | playerid, 43 | textid, 44 | Plugin_Settings::file.c_str(), 45 | Plugin_Settings::line 46 | ); 47 | } 48 | else if (type == LogType::FIND_PLAYER_TEXT) 49 | { 50 | sampgdk::logprintf("[textdraw.streamer] %s: No such id was found. (playerid: %d, textId: %d) (%s:%d)" 51 | , 52 | funcs.c_str(), 53 | playerid, 54 | textid, 55 | Plugin_Settings::file.c_str(), 56 | Plugin_Settings::line 57 | ); 58 | } 59 | else if (type == LogType::SHOW_LIMIT_PLAYER) 60 | { 61 | sampgdk::logprintf("[textdraw.streamer] %s: A maximum of %d textdraws can be displayed on a player. (playerid: %d, textId: %d) (%s:%d)" 62 | , 63 | funcs.c_str(), 64 | MAX_PLAYER_TEXT_DRAWS, 65 | playerid, 66 | textid, 67 | Plugin_Settings::file.c_str(), 68 | Plugin_Settings::line 69 | ); 70 | } 71 | else if (type == LogType::FIND_GLOBAL_TEXT) 72 | { 73 | sampgdk::logprintf("[textdraw.streamer] %s: No such id was found. (textId: %d) (%s:%d)" 74 | , 75 | funcs.c_str(), 76 | textid, 77 | Plugin_Settings::file.c_str(), 78 | Plugin_Settings::line 79 | ); 80 | } 81 | else if (type == LogType::INVALID_TYPE) 82 | { 83 | sampgdk::logprintf("[textdraw.streamer] %s: Type format is invalid. (%s:%d)" 84 | , 85 | funcs.c_str(), 86 | Plugin_Settings::file.c_str(), 87 | Plugin_Settings::line 88 | ); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/plugin.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------- 2 | // 3 | // SA-MP Multiplayer Modification For GTA:SA 4 | // Copyright 2004-2009 SA-MP Team 5 | // 6 | //---------------------------------------------------------- 7 | 8 | #include "plugincommon.h" 9 | #include "amx/amx.h" 10 | 11 | //---------------------------------------------------------- 12 | // EOF 13 | -------------------------------------------------------------------------------- /src/plugin_version.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define MINOR (2) 18 | #define MAJOR (0) 19 | #define PATCH (3) -------------------------------------------------------------------------------- /src/plugincommon.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------- 2 | // 3 | // SA-MP Multiplayer Modification For GTA:SA 4 | // Copyright 2004-2009 SA-MP Team 5 | // 6 | //---------------------------------------------------------- 7 | 8 | #pragma once 9 | 10 | //---------------------------------------------------------- 11 | 12 | #define SAMP_PLUGIN_VERSION 0x0200 13 | 14 | //---------------------------------------------------------- 15 | 16 | #ifdef __cplusplus 17 | #define PLUGIN_EXTERN_C extern "C" 18 | #else 19 | #define PLUGIN_EXTERN_C 20 | #endif 21 | 22 | #if defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD__) || defined(__OpenBSD__) 23 | #ifndef __GNUC__ 24 | #pragma message "Warning: Not using a GNU compiler." 25 | #endif 26 | #define PLUGIN_CALL 27 | #ifndef SAMPSVR 28 | // Compile code with -fvisibility=hidden to hide non-exported functions. 29 | #define PLUGIN_EXPORT PLUGIN_EXTERN_C __attribute__((visibility("default"))) 30 | #else 31 | #define PLUGIN_EXPORT PLUGIN_EXTERN_C 32 | #endif 33 | #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 34 | #ifndef _MSC_VER 35 | #pragma message "Warning: Not using a VC++ compiler." 36 | #endif 37 | #define PLUGIN_CALL __stdcall 38 | #define PLUGIN_EXPORT PLUGIN_EXTERN_C 39 | #else 40 | #error "You must define one of WIN32, LINUX or FREEBSD" 41 | #endif 42 | 43 | //---------------------------------------------------------- 44 | 45 | enum SUPPORTS_FLAGS 46 | { 47 | SUPPORTS_VERSION = SAMP_PLUGIN_VERSION, 48 | SUPPORTS_VERSION_MASK = 0xffff, 49 | SUPPORTS_AMX_NATIVES = 0x10000, 50 | SUPPORTS_PROCESS_TICK = 0x20000 51 | }; 52 | 53 | //---------------------------------------------------------- 54 | 55 | enum PLUGIN_DATA_TYPE 56 | { 57 | // For some debugging 58 | PLUGIN_DATA_LOGPRINTF = 0x00, // void (*logprintf)(char* format, ...) 59 | 60 | // AMX 61 | PLUGIN_DATA_AMX_EXPORTS = 0x10, // void* AmxFunctionTable[] (see PLUGIN_AMX_EXPORT) 62 | PLUGIN_DATA_CALLPUBLIC_FS = 0x11, // int (*AmxCallPublicFilterScript)(char *szFunctionName) 63 | PLUGIN_DATA_CALLPUBLIC_GM = 0x12, // int (*AmxCallPublicGameMode)(char *szFunctionName) 64 | 65 | }; 66 | 67 | //---------------------------------------------------------- 68 | 69 | enum PLUGIN_AMX_EXPORT 70 | { 71 | PLUGIN_AMX_EXPORT_Align16 = 0, 72 | PLUGIN_AMX_EXPORT_Align32 = 1, 73 | PLUGIN_AMX_EXPORT_Align64 = 2, 74 | PLUGIN_AMX_EXPORT_Allot = 3, 75 | PLUGIN_AMX_EXPORT_Callback = 4, 76 | PLUGIN_AMX_EXPORT_Cleanup = 5, 77 | PLUGIN_AMX_EXPORT_Clone = 6, 78 | PLUGIN_AMX_EXPORT_Exec = 7, 79 | PLUGIN_AMX_EXPORT_FindNative = 8, 80 | PLUGIN_AMX_EXPORT_FindPublic = 9, 81 | PLUGIN_AMX_EXPORT_FindPubVar = 10, 82 | PLUGIN_AMX_EXPORT_FindTagId = 11, 83 | PLUGIN_AMX_EXPORT_Flags = 12, 84 | PLUGIN_AMX_EXPORT_GetAddr = 13, 85 | PLUGIN_AMX_EXPORT_GetNative = 14, 86 | PLUGIN_AMX_EXPORT_GetPublic = 15, 87 | PLUGIN_AMX_EXPORT_GetPubVar = 16, 88 | PLUGIN_AMX_EXPORT_GetString = 17, 89 | PLUGIN_AMX_EXPORT_GetTag = 18, 90 | PLUGIN_AMX_EXPORT_GetUserData = 19, 91 | PLUGIN_AMX_EXPORT_Init = 20, 92 | PLUGIN_AMX_EXPORT_InitJIT = 21, 93 | PLUGIN_AMX_EXPORT_MemInfo = 22, 94 | PLUGIN_AMX_EXPORT_NameLength = 23, 95 | PLUGIN_AMX_EXPORT_NativeInfo = 24, 96 | PLUGIN_AMX_EXPORT_NumNatives = 25, 97 | PLUGIN_AMX_EXPORT_NumPublics = 26, 98 | PLUGIN_AMX_EXPORT_NumPubVars = 27, 99 | PLUGIN_AMX_EXPORT_NumTags = 28, 100 | PLUGIN_AMX_EXPORT_Push = 29, 101 | PLUGIN_AMX_EXPORT_PushArray = 30, 102 | PLUGIN_AMX_EXPORT_PushString = 31, 103 | PLUGIN_AMX_EXPORT_RaiseError = 32, 104 | PLUGIN_AMX_EXPORT_Register = 33, 105 | PLUGIN_AMX_EXPORT_Release = 34, 106 | PLUGIN_AMX_EXPORT_SetCallback = 35, 107 | PLUGIN_AMX_EXPORT_SetDebugHook = 36, 108 | PLUGIN_AMX_EXPORT_SetString = 37, 109 | PLUGIN_AMX_EXPORT_SetUserData = 38, 110 | PLUGIN_AMX_EXPORT_StrLen = 39, 111 | PLUGIN_AMX_EXPORT_UTF8Check = 40, 112 | PLUGIN_AMX_EXPORT_UTF8Get = 41, 113 | PLUGIN_AMX_EXPORT_UTF8Len = 42, 114 | PLUGIN_AMX_EXPORT_UTF8Put = 43, 115 | }; 116 | 117 | //---------------------------------------------------------- 118 | // EOF 119 | -------------------------------------------------------------------------------- /src/service.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nexquery/samp-textdraw-streamer/f27b79a38ada8120527e2ec4bc63c6c53c4dbf80/src/service.cpp -------------------------------------------------------------------------------- /src/service.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include "sampgdk.hpp" 20 | 21 | namespace service 22 | { 23 | void setInt(AMX* amx, cell output, int value); 24 | void setFloat(AMX* amx, cell output, float value); 25 | void setString(AMX* amx, cell output, cell size, std::string string); 26 | std::string getString(AMX* amx, cell input); 27 | std::string formattedString(AMX* amx, cell* params, cell text_index, int32_t args_offset); 28 | }; -------------------------------------------------------------------------------- /src/slot_manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "slot_manager.hpp" 18 | 19 | /*** 20 | * .d8888b. 888 888 888 21 | * d88P Y88b 888 888 888 22 | * 888 888 888 888 888 23 | * 888 888 .d88b. 88888b. 8888b. 888 24 | * 888 88888 888 d88""88b 888 "88b "88b 888 25 | * 888 888 888 888 888 888 888 .d888888 888 26 | * Y88b d88P 888 Y88..88P 888 d88P 888 888 888 27 | * "Y8888P88 888 "Y88P" 88888P" "Y888888 888 28 | * 29 | */ 30 | 31 | int slot_manager_global::next_Id; 32 | std::priority_queue, std::greater> slot_manager_global::global_ids; 33 | 34 | int slot_manager_global::get_id() 35 | { 36 | if (slot_manager_global::global_ids.empty()) { 37 | return 1 + slot_manager_global::next_Id++; 38 | } 39 | 40 | int low_id = slot_manager_global::global_ids.top(); 41 | slot_manager_global::global_ids.pop(); 42 | 43 | return low_id; 44 | } 45 | 46 | void slot_manager_global::remove_id(int value) 47 | { 48 | slot_manager_global::global_ids.push(value); 49 | } 50 | 51 | 52 | /*** 53 | * 8888888b. 888 54 | * 888 Y88b 888 55 | * 888 888 888 56 | * 888 d88P 888 8888b. 888 888 .d88b. 888d888 57 | * 8888888P" 888 "88b 888 888 d8P Y8b 888P" 58 | * 888 888 .d888888 888 888 88888888 888 59 | * 888 888 888 888 Y88b 888 Y8b. 888 60 | * 888 888 "Y888888 "Y88888 "Y8888 888 61 | * 888 62 | * Y8b d88P 63 | * "Y88P" 64 | */ 65 | 66 | std::map slot_manager_player::next_Id; 67 | std::map, std::greater>> slot_manager_player::p_Ids; 68 | 69 | int slot_manager_player::get_id(int playerid) 70 | { 71 | if (slot_manager_player::p_Ids[playerid].empty()) { 72 | return 1 + slot_manager_player::next_Id[playerid]++; 73 | } 74 | 75 | int low_id = slot_manager_player::p_Ids[playerid].top(); 76 | slot_manager_player::p_Ids[playerid].pop(); 77 | 78 | return low_id; 79 | } 80 | 81 | void slot_manager_player::remove_id(int playerid, int value) 82 | { 83 | slot_manager_player::p_Ids[playerid].push(value); 84 | } 85 | 86 | void slot_manager_player::reset_id(int playerid) 87 | { 88 | slot_manager_player::next_Id[playerid] = 0; 89 | slot_manager_player::p_Ids[playerid] = std::priority_queue, std::greater>(); 90 | } -------------------------------------------------------------------------------- /src/slot_manager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | class slot_manager_player 23 | { 24 | public: 25 | static int get_id(int playerid); 26 | static void remove_id(int playerid, int value); 27 | static void reset_id(int playerid); 28 | 29 | private: 30 | static std::map next_Id; 31 | static std::map, std::greater>> p_Ids; 32 | }; 33 | 34 | class slot_manager_global 35 | { 36 | public: 37 | static int get_id(); 38 | static void remove_id(int value); 39 | private: 40 | static int next_Id; 41 | static std::priority_queue, std::greater> global_ids; 42 | }; -------------------------------------------------------------------------------- /src/textdraw-streamer.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | Supports 3 | Load 4 | Unload 5 | AmxLoad 6 | AmxUnload 7 | ProcessTick 8 | OnPlayerConnect 9 | OnPlayerDisconnect 10 | OnPlayerClickTextDraw 11 | OnPlayerClickPlayerTextDraw -------------------------------------------------------------------------------- /src/textdraw_data.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "textdraw_data.hpp" 18 | #include "slot_manager.hpp" 19 | #include "sampgdk.hpp" 20 | 21 | 22 | /*** 23 | * .d8888b. 888 888 888 24 | * d88P Y88b 888 888 888 25 | * 888 888 888 888 888 26 | * 888 888 .d88b. 88888b. 8888b. 888 27 | * 888 88888 888 d88""88b 888 "88b "88b 888 28 | * 888 888 888 888 888 888 888 .d888888 888 29 | * Y88b d88P 888 Y88..88P 888 d88P 888 888 888 30 | * "Y8888P88 888 "Y88P" 88888P" "Y888888 888 31 | * 32 | * 33 | * 34 | */ 35 | 36 | DefaultText GlobalText::Default; 37 | std::unordered_set GlobalText::PlayerList; 38 | std::unordered_map* GlobalText::gText = new std::unordered_map(); 39 | std::map> GlobalText::gTextVisible; 40 | 41 | void GlobalText::Destroy() 42 | { 43 | if (!gText->empty()) 44 | { 45 | for (auto it = gText->begin(); it != gText->end(); it++) 46 | { 47 | // Extra id 48 | delete it->second->extra_id; 49 | 50 | // Array data 51 | delete it->second->array_data; 52 | 53 | // Text data 54 | delete it->second; 55 | } 56 | 57 | delete gText; 58 | gText = nullptr; 59 | } 60 | } 61 | 62 | void GlobalText::Reload(std::unordered_map::iterator it) 63 | { 64 | if (it->second->real_id == INVALID_DYNAMIC_PLAYER_TEXTDRAW) 65 | { 66 | int text_id = TextDrawCreate(it->second->create_x, it->second->create_y, it->second->text.c_str()); 67 | 68 | if (text_id == INVALID_TEXT_DRAW) 69 | { 70 | sampgdk::logprintf("[textdraw.streamer] GlobalText::Reload: A maximum of %d global textdraws can be created.", MAX_TEXT_DRAWS); 71 | return; 72 | } 73 | 74 | if (it->second->lettersize_x != GlobalText::Default.lettersize_x || it->second->lettersize_y != GlobalText::Default.lettersize_y) { 75 | TextDrawLetterSize(text_id, it->second->lettersize_x, it->second->lettersize_y); 76 | } 77 | 78 | if (it->second->textsize_x != GlobalText::Default.textsize_x || it->second->textsize_y != GlobalText::Default.textsize_y) { 79 | TextDrawTextSize(text_id, it->second->textsize_x, it->second->textsize_y); 80 | } 81 | 82 | if (it->second->alignment != GlobalText::Default.alignment) { 83 | TextDrawAlignment(text_id, it->second->alignment); 84 | } 85 | 86 | if (it->second->color != GlobalText::Default.color) { 87 | TextDrawColor(text_id, it->second->color); 88 | } 89 | 90 | if (it->second->usebox != GlobalText::Default.usebox) { 91 | TextDrawUseBox(text_id, it->second->usebox); 92 | } 93 | 94 | if (it->second->boxcolor != GlobalText::Default.boxcolor) { 95 | TextDrawBoxColor(text_id, it->second->boxcolor); 96 | } 97 | 98 | if (it->second->shadow != GlobalText::Default.shadow) { 99 | TextDrawSetShadow(text_id, it->second->shadow); 100 | } 101 | 102 | if (it->second->outline != GlobalText::Default.outline) { 103 | TextDrawSetOutline(text_id, it->second->outline); 104 | } 105 | 106 | if (it->second->backgroundcolor != GlobalText::Default.backgroundcolor) { 107 | TextDrawBackgroundColor(text_id, it->second->backgroundcolor); 108 | } 109 | 110 | if (it->second->font != GlobalText::Default.font) { 111 | TextDrawFont(text_id, it->second->font); 112 | } 113 | 114 | if (it->second->proportional != GlobalText::Default.proportional) { 115 | TextDrawSetProportional(text_id, it->second->proportional); 116 | } 117 | 118 | if (it->second->selectable != GlobalText::Default.selectable) { 119 | TextDrawSetSelectable(text_id, it->second->selectable); 120 | } 121 | 122 | if (it->second->font == TEXT_DRAW_FONT_MODEL_PREVIEW) 123 | { 124 | if (it->second->modelindex != GlobalText::Default.modelindex) { 125 | TextDrawSetPreviewModel(text_id, it->second->modelindex); 126 | } 127 | 128 | if (it->second->fRotX != GlobalText::Default.fRotX || it->second->fRotY != GlobalText::Default.fRotY || it->second->fRotZ != GlobalText::Default.fRotZ || it->second->fZoom != GlobalText::Default.fZoom) { 129 | TextDrawSetPreviewRot(text_id, it->second->fRotX, it->second->fRotY, it->second->fRotZ, it->second->fZoom); 130 | } 131 | 132 | if (it->second->veh_col1 != GlobalText::Default.veh_col1 || it->second->veh_col2 != GlobalText::Default.veh_col2) { 133 | TextDrawSetPreviewVehCol( text_id, it->second->veh_col1, it->second->veh_col2); 134 | } 135 | } 136 | 137 | it->second->real_id = text_id; 138 | } 139 | } 140 | 141 | /*** 142 | * 8888888b. 888 143 | * 888 Y88b 888 144 | * 888 888 888 145 | * 888 d88P 888 8888b. 888 888 .d88b. 888d888 146 | * 8888888P" 888 "88b 888 888 d8P Y8b 888P" 147 | * 888 888 .d888888 888 888 88888888 888 148 | * 888 888 888 888 Y88b 888 Y8b. 888 149 | * 888 888 "Y888888 "Y88888 "Y8888 888 150 | * 888 151 | * Y8b d88P 152 | * "Y88P" 153 | */ 154 | 155 | DefaultText PlayerText::Default; 156 | std::unordered_map*> PlayerText::pText; 157 | 158 | void PlayerText::Destroy(int playerid) 159 | { 160 | if (playerid >= 0 && playerid < MAX_PLAYERS) 161 | { 162 | // Eger veri yoksa alt islemleri calistirma 163 | if (pText[playerid] == nullptr) { 164 | return; 165 | } 166 | 167 | // Sadece oyuncu kimliginin icerigini temizle 168 | for (auto p = pText[playerid]->begin(); p != pText[playerid]->end(); p++) 169 | { 170 | // Extra id kaldir 171 | delete p->second->extra_id; 172 | 173 | // Array verilerini kaldir 174 | delete p->second->array_data; 175 | 176 | // Data daki verileri kaldir 177 | delete p->second; 178 | } 179 | 180 | // Pointeri kaldir 181 | delete pText[playerid]; 182 | pText[playerid] = nullptr; 183 | 184 | // Slot manager da ki kimlikleri temizle 185 | slot_manager_player::reset_id(playerid); 186 | } 187 | else 188 | { 189 | // playerid degeri -1 ve alti olursa tum oyuncu havuzunu temizle 190 | for (auto it = pText.begin(); it != pText.end(); it++) 191 | { 192 | if (pText[it->first] == nullptr) { 193 | continue; 194 | } 195 | 196 | for (auto p = pText[it->first]->begin(); p != pText[it->first]->end(); p++) 197 | { 198 | // Extra id kaldir 199 | delete p->second->extra_id; 200 | 201 | // Array verilerini kaldir 202 | delete p->second->array_data; 203 | 204 | // Data daki verileri kaldir 205 | delete p->second; 206 | } 207 | 208 | // Pointeri kaldir 209 | delete pText[it->first]; 210 | pText[playerid] = nullptr; 211 | 212 | // Slot manager da ki kimlikleri temizle 213 | slot_manager_player::reset_id(it->first); 214 | } 215 | 216 | // Tum pointer listesini temizle 217 | pText.clear(); 218 | } 219 | } 220 | 221 | void PlayerText::Reload(int playerid, std::unordered_map::iterator it) 222 | { 223 | if (it->second->real_id == INVALID_DYNAMIC_PLAYER_TEXTDRAW) 224 | { 225 | int text_id = CreatePlayerTextDraw(playerid, it->second->create_x, it->second->create_y, it->second->text.c_str()); 226 | 227 | if (it->second->lettersize_x != PlayerText::Default.lettersize_x || it->second->lettersize_y != PlayerText::Default.lettersize_y) { 228 | PlayerTextDrawLetterSize(playerid, text_id, it->second->lettersize_x, it->second->lettersize_y); 229 | } 230 | 231 | if (it->second->textsize_x != PlayerText::Default.textsize_x || it->second->textsize_y != PlayerText::Default.textsize_y) { 232 | PlayerTextDrawTextSize(playerid, text_id, it->second->textsize_x, it->second->textsize_y); 233 | } 234 | 235 | if (it->second->alignment != PlayerText::Default.alignment) { 236 | PlayerTextDrawAlignment(playerid, text_id, it->second->alignment); 237 | } 238 | 239 | if (it->second->color != PlayerText::Default.color) { 240 | PlayerTextDrawColor(playerid, text_id, it->second->color); 241 | } 242 | 243 | if (it->second->usebox != PlayerText::Default.usebox) { 244 | PlayerTextDrawUseBox(playerid, text_id, it->second->usebox); 245 | } 246 | 247 | if (it->second->boxcolor != PlayerText::Default.boxcolor) { 248 | PlayerTextDrawBoxColor(playerid, text_id, it->second->boxcolor); 249 | } 250 | 251 | if (it->second->shadow != PlayerText::Default.shadow) { 252 | PlayerTextDrawSetShadow(playerid, text_id, it->second->shadow); 253 | } 254 | 255 | if (it->second->outline != PlayerText::Default.outline) { 256 | PlayerTextDrawSetOutline(playerid, text_id, it->second->outline); 257 | } 258 | 259 | if (it->second->backgroundcolor != PlayerText::Default.backgroundcolor) { 260 | PlayerTextDrawBackgroundColor(playerid, text_id, it->second->backgroundcolor); 261 | } 262 | 263 | if (it->second->font != PlayerText::Default.font) { 264 | PlayerTextDrawFont(playerid, text_id, it->second->font); 265 | } 266 | 267 | if (it->second->proportional != PlayerText::Default.proportional) { 268 | PlayerTextDrawSetProportional(playerid, text_id, it->second->proportional); 269 | } 270 | 271 | if (it->second->selectable != PlayerText::Default.selectable) { 272 | PlayerTextDrawSetSelectable(playerid, text_id, it->second->selectable); 273 | } 274 | 275 | if (it->second->font == TEXT_DRAW_FONT_MODEL_PREVIEW) 276 | { 277 | if (it->second->modelindex != PlayerText::Default.modelindex) { 278 | PlayerTextDrawSetPreviewModel(playerid, text_id, it->second->modelindex); 279 | } 280 | 281 | if (it->second->fRotX != PlayerText::Default.fRotX || it->second->fRotY != PlayerText::Default.fRotY || it->second->fRotZ != PlayerText::Default.fRotZ || it->second->fZoom != PlayerText::Default.fZoom) { 282 | PlayerTextDrawSetPreviewRot(playerid, text_id, it->second->fRotX, it->second->fRotY, it->second->fRotZ, it->second->fZoom); 283 | } 284 | 285 | if (it->second->veh_col1 != PlayerText::Default.veh_col1 || it->second->veh_col2 != PlayerText::Default.veh_col2) { 286 | PlayerTextDrawSetPreviewVehCol(playerid, text_id, it->second->veh_col1, it->second->veh_col2); 287 | } 288 | } 289 | 290 | it->second->real_id = text_id; 291 | PlayerTextDrawShow(playerid, it->second->real_id); 292 | } 293 | } -------------------------------------------------------------------------------- /src/textdraw_data.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Burak (Nexor) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define INVALID_DYNAMIC_PLAYER_TEXTDRAW (-1) 26 | 27 | enum TDStreamer_Type 28 | { 29 | GLOBAL = 0, 30 | PLAYER 31 | }; 32 | 33 | enum LogType 34 | { 35 | // Player 36 | CREATE_PLAYER_TEXTDRAW, 37 | FIND_PLAYER_TEXT, 38 | SHOW_LIMIT_PLAYER, 39 | 40 | // Global 41 | FIND_GLOBAL_TEXT, 42 | 43 | // Data 44 | INVALID_TYPE, 45 | }; 46 | 47 | struct DefaultText 48 | { 49 | float lettersize_x = 0.0; 50 | float lettersize_y = 0.0; 51 | float textsize_x = 0.0; 52 | float textsize_y = 0.0; 53 | int alignment = 1; 54 | int color = -2; 55 | int usebox = 0; 56 | int boxcolor = -2; 57 | int shadow = 2; 58 | int outline = 0; 59 | int backgroundcolor = -2; 60 | int font = 1; 61 | int proportional = 1; 62 | int selectable = 0; 63 | int modelindex = 0; 64 | float fRotX = 0.0; 65 | float fRotY = 0.0; 66 | float fRotZ = 0.0; 67 | float fZoom = 1.0; 68 | int veh_col1 = -2; 69 | int veh_col2 = -2; 70 | }; 71 | 72 | struct Text_Data 73 | { 74 | int real_id{}; 75 | float create_x{}; 76 | float create_y{}; 77 | std::string text; 78 | float lettersize_x{}; 79 | float lettersize_y{}; 80 | float textsize_x{}; 81 | float textsize_y{}; 82 | int alignment{}; 83 | int color{}; 84 | int usebox{}; 85 | int boxcolor{}; 86 | int shadow{}; 87 | int outline{}; 88 | int backgroundcolor{}; 89 | int font{}; 90 | int proportional{}; 91 | int selectable{}; 92 | int modelindex{}; 93 | float fRotX{}; 94 | float fRotY{}; 95 | float fRotZ{}; 96 | float fZoom{}; 97 | int veh_col1{}; 98 | int veh_col2{}; 99 | std::map* extra_id{}; 100 | float float_data{}; 101 | std::vector* array_data{}; 102 | }; 103 | 104 | class Plugin_Settings 105 | { 106 | public: 107 | static bool logMode; 108 | static std::string file; 109 | static int line; 110 | static void ILogger(LogType type, std::string funcs, int playerid, int textid); 111 | }; 112 | 113 | class PlayerText 114 | { 115 | public: 116 | static DefaultText Default; 117 | static std::unordered_map*> pText; 118 | static void Destroy(int playerid); 119 | static void Reload(int playerid, std::unordered_map::iterator it); 120 | }; 121 | 122 | class GlobalText 123 | { 124 | public: 125 | static DefaultText Default; 126 | static std::unordered_set PlayerList; 127 | static std::unordered_map* gText; 128 | static std::map> gTextVisible; 129 | static void Destroy(); 130 | static void Reload(std::unordered_map::iterator it); 131 | }; --------------------------------------------------------------------------------