10
10
using CounterStrikeSharp . API . Core . Plugin ;
11
11
12
12
namespace CustomCommands . Services ;
13
- public class ReplaceTagsFunctions : IReplaceTagsFunctions
13
+ public partial class ReplaceTagsFunctions : IReplaceTagsFunctions
14
14
{
15
- private readonly IPluginGlobals PluginGlobals ;
16
- private readonly PluginContext PluginContext ;
17
- private readonly ILogger < CustomCommands > Logger ;
15
+ private readonly IPluginGlobals _pluginGlobals ;
16
+ private readonly PluginContext _pluginContext ;
17
+ private readonly ILogger < CustomCommands > _logger ;
18
18
19
19
public ReplaceTagsFunctions ( IPluginGlobals PluginGlobals , IPluginContext PluginContext ,
20
20
ILogger < CustomCommands > Logger )
21
21
{
22
- this . PluginGlobals = PluginGlobals ;
23
- this . PluginContext = ( PluginContext as PluginContext ) ! ;
24
- this . Logger = Logger ;
22
+ _pluginGlobals = PluginGlobals ;
23
+ _pluginContext = ( PluginContext as PluginContext ) ! ;
24
+ _logger = Logger ;
25
25
}
26
26
27
-
28
-
29
- /// <summary>
30
- /// Replaces tags in the input array with their corresponding values.
31
- /// </summary>
32
- /// <param name="input">The array of strings containing tags to be replaced.</param>
33
- /// <param name="player">The CCSPlayerController object used for tag replacement.</param>
34
- /// <returns>The array of strings with tags replaced.</returns>
35
27
public string [ ] ReplaceTags ( dynamic input , CCSPlayerController player )
36
28
{
37
- List < string > output = WrappedLine ( input ) ;
29
+ var output = WrappedLine ( input ) ;
38
30
39
31
for ( int i = 0 ; i < output . Count ; i ++ )
40
32
output [ i ] = ReplaceLanguageTags ( output [ i ] ) ;
@@ -44,58 +36,102 @@ public string[] ReplaceTags(dynamic input, CCSPlayerController player)
44
36
for ( int i = 0 ; i < output . Count ; i ++ )
45
37
{
46
38
output [ i ] = ReplaceMessageTags ( output [ i ] , player , false ) ;
39
+ output [ i ] = ReplaceRandomTags ( output [ i ] ) ;
47
40
output [ i ] = ReplaceColorTags ( output [ i ] ) ;
48
41
}
49
42
50
- return output . ToArray < string > ( ) ;
43
+ return output . ToArray ( ) ;
51
44
}
52
45
53
- /// <summary>
54
- /// Replaces language tags in the input string with the corresponding localized value.
55
- /// Language tags are defined within curly braces, e.g. "{LANG=LocalizerTag}".
56
- /// If a language tag is found, it is replaced with the localized value from the CustomCommands plugin's Localizer.
57
- /// If the localized value is not found, a default message is returned.
58
- /// </summary>
59
- /// <param name="input">The input string to process.</param>
60
- /// <returns>The input string with language tags replaced with localized values.</returns>
46
+ [ GeneratedRegex ( @"\{LANG=(.*?)\}" ) ]
47
+ private static partial Regex ReplaceLanguageTagsRegex ( ) ;
48
+
61
49
public string ReplaceLanguageTags ( string input )
62
50
{
63
- CustomCommands plugin = ( PluginContext . Plugin as CustomCommands ) ! ;
64
-
65
- // Define the regex pattern to find "{LANG=...}"
66
- string pattern = @"\{LANG=(.*?)\}" ;
67
-
68
51
// Use Regex to find matches
69
- Match match = Regex . Match ( input , pattern ) ;
52
+ var match = ReplaceLanguageTagsRegex ( ) . Match ( input ) ;
70
53
71
54
// Check if a match is found
72
55
if ( match . Success )
73
56
{
74
57
// Return the group captured in the regex, which is the string after "="
75
- string lang = match . Groups [ 1 ] . Value ;
76
- return input . Replace ( match . Value , plugin . Localizer [ lang ] ?? "<LANG in CustomCommands/lang/<language.json> not found>" ) ;
58
+ var lang = match . Groups [ 1 ] . Value ;
59
+ var context = ( _pluginContext . Plugin as CustomCommands ) ! ;
60
+
61
+ return input . Replace ( match . Value , context . Localizer [ lang ] ?? "<LANG in CustomCommands/lang/<language.json> not found>" ) ;
77
62
}
78
63
else
79
64
{
80
65
// Return the original string if no match is found
81
66
return input ;
82
67
}
83
68
}
84
-
69
+
85
70
/// <summary>
86
- /// Replaces tags in the input string with corresponding values based on the provided player information.
71
+ /// Use regex to find the RNDNO tag pattern {RNDNO={min, max}}
87
72
/// </summary>
88
- /// <param name="input">The input string containing tags to be replaced.</param>
89
- /// <param name="player">The CCSPlayerController object representing the player.</param>
90
- /// <param name="safety">A boolean value indicating whether to replace the {PLAYERNAME} tag. Default is true.</param>
91
- /// <returns>The modified string with replaced tags.</returns>
73
+ /// <returns></returns>
74
+ [ GeneratedRegex ( @"\{RNDNO=\((\d+(?:\.\d+)?),\s*(\d+(?:\.\d+)?)\)\}" ) ]
75
+ private static partial Regex ReplaceRandomTagsRegex ( ) ;
76
+
77
+ public string ReplaceRandomTags ( string message )
78
+ {
79
+ // Replace all occurrences of the RNDNO tag in the message
80
+ var match = ReplaceRandomTagsRegex ( ) . Match ( message ) ;
81
+
82
+ // Extract min and max from the regex match groups
83
+ string minStr = match . Groups [ 1 ] . Value ;
84
+ string maxStr = match . Groups [ 2 ] . Value ;
85
+
86
+ // Determine if the min and max are integers or floats
87
+ bool isMinFloat = float . TryParse ( minStr , out float minFloat ) ;
88
+ bool isMaxFloat = float . TryParse ( maxStr , out float maxFloat ) ;
89
+
90
+ var random = new Random ( ) ;
91
+
92
+ if ( isMinFloat || isMaxFloat )
93
+ {
94
+ // Generate a random float between min and max (inclusive)
95
+ float randomFloat = ( float ) ( random . NextDouble ( ) * ( maxFloat - minFloat ) + minFloat ) ;
96
+
97
+ // Determine the maximum precision from the min and max values
98
+ int maxDecimalPlaces = Math . Max ( GetDecimalPlaces ( minStr ) , GetDecimalPlaces ( maxStr ) ) ;
99
+
100
+ // Use the determined precision to format the float
101
+ message = message . Replace ( match . Value , randomFloat . ToString ( $ "F{ maxDecimalPlaces } ") ) ;
102
+ }
103
+ else
104
+ {
105
+ // Parse as integers
106
+ int min = int . Parse ( minStr ) ;
107
+ int max = int . Parse ( maxStr ) ;
108
+
109
+ // Generate a random integer between min and max (inclusive)
110
+ int randomValue = random . Next ( min , max + 1 ) ; // max is exclusive, so add 1
111
+ message = message . Replace ( match . Value , randomValue . ToString ( ) ) ;
112
+ }
113
+
114
+ return message ;
115
+ }
116
+
117
+ // Method to get the number of decimal places in a number string
118
+ private static int GetDecimalPlaces ( string numberStr )
119
+ {
120
+ int decimalIndex = numberStr . IndexOf ( '.' ) ;
121
+ if ( decimalIndex == - 1 )
122
+ {
123
+ return 0 ; // No decimal point, return 0
124
+ }
125
+ return numberStr . Length - decimalIndex - 1 ; // Count digits after the decimal point
126
+ }
127
+
92
128
public string ReplaceMessageTags ( string input , CCSPlayerController player , bool safety = true )
93
129
{
94
- SteamID steamId = new SteamID ( player . SteamID ) ;
130
+ var steamId = new SteamID ( player . SteamID ) ;
95
131
96
132
Dictionary < string , string > replacements = new ( )
97
133
{
98
- { "{PREFIX}" , PluginGlobals . Config . Prefix ?? "<PREFIX not found>" } ,
134
+ { "{PREFIX}" , _pluginGlobals . Config . Prefix ?? "<PREFIX not found>" } ,
99
135
{ "{MAP}" , NativeAPI . GetMapName ( ) ?? "<MAP not found>" } ,
100
136
{ "{TIME}" , DateTime . Now . ToString ( "HH:mm:ss" ) ?? "<TIME not found>" } ,
101
137
{ "{DATE}" , DateTime . Now . ToString ( "dd.MM.yyyy" ) ?? "<DATE not found>" } ,
@@ -109,7 +145,7 @@ public string ReplaceMessageTags(string input, CCSPlayerController player, bool
109
145
{ "{PORT}" , ConVar . Find ( "hostport" ) ! . GetPrimitiveValue < int > ( ) . ToString ( ) ?? "<PORT not found>" } ,
110
146
{ "{MAXPLAYERS}" , Server . MaxPlayers . ToString ( ) ?? "<MAXPLAYERS not found>" } ,
111
147
{ "{PLAYERS}" ,
112
- Utilities . GetPlayers ( ) . Count ( u => u . PlayerPawn . Value != null && u . PlayerPawn . Value . IsValid ) . ToString ( ) ?? "<PLAYERS not found>" }
148
+ Utilities . GetPlayers ( ) . Count ( u => u . PlayerPawn . Value != null && u . PlayerPawn . Value . IsValid ) . ToString ( ) ?? "<PLAYERS not found>" } ,
113
149
} ;
114
150
115
151
// Prevent vounrability by not replacing {PLAYERNAME} if safety is true/ServerCommands are being executed
@@ -155,46 +191,41 @@ public string ReplaceColorTags(string input)
155
191
return input ;
156
192
}
157
193
158
- /// <summary>
159
- /// Splits the input into an array of strings. If the input is a string, it will be split by newlines. If the input is an array, each element will be split by newlines.
160
- /// </summary>
161
- /// <param name="input">This should be a string[] or a string</param>
162
- /// <returns>An array of strings representing the lines of the input.</returns>
163
194
public List < string > WrappedLine ( dynamic input )
164
195
{
165
- List < string > output = new List < string > ( ) ;
196
+ var output = new List < string > ( ) ;
166
197
167
198
if ( input is JsonElement jsonElement )
168
199
{
169
200
switch ( jsonElement . ValueKind )
170
201
{
171
202
case JsonValueKind . String :
172
- string result = jsonElement . GetString ( ) ! ;
203
+ var result = jsonElement . GetString ( ) ! ;
173
204
output . AddRange ( result . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ) ;
174
205
break ;
175
206
case JsonValueKind . Array :
176
207
foreach ( var arrayElement in jsonElement . EnumerateArray ( ) )
177
208
{
178
- string [ ] lines = arrayElement . GetString ( ) ? . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ?? Array . Empty < string > ( ) ;
209
+ var lines = arrayElement . GetString ( ) ? . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ?? Array . Empty < string > ( ) ;
179
210
output . AddRange ( lines ) ;
180
211
}
181
212
break ;
182
213
183
214
default :
184
- Logger . LogError ( $ "{ PluginGlobals . Config . LogPrefix } Message is not a string or array") ;
215
+ _logger . LogError ( $ "{ _pluginGlobals . Config . LogPrefix } Message is not a string or array") ;
185
216
break ;
186
217
}
187
218
} else if ( input is Array inputArray )
188
219
{
189
220
foreach ( string arrayElement in inputArray )
190
221
{
191
- string [ ] lines = arrayElement . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ?? Array . Empty < string > ( ) ;
222
+ var lines = arrayElement . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ?? Array . Empty < string > ( ) ;
192
223
output . AddRange ( lines ) ;
193
224
}
194
225
}
195
226
else
196
227
{
197
- Logger . LogError ( $ "{ PluginGlobals . Config . LogPrefix } Invalid input type") ;
228
+ _logger . LogError ( $ "{ _pluginGlobals . Config . LogPrefix } Invalid input type") ;
198
229
}
199
230
200
231
return output ;
@@ -206,9 +237,9 @@ public List<string> WrappedLine(dynamic input)
206
237
/// </summary>
207
238
/// <param name="input"></param>
208
239
/// <returns></returns>
209
- private string PadLeftColorTag ( string input )
240
+ private static string PadLeftColorTag ( string input )
210
241
{
211
- string [ ] colorTagList = new string [ ] {
242
+ var colorTagList = new string [ ] {
212
243
"{DEFAULT}" ,
213
244
"{WHITE}" ,
214
245
"{DARKRED}" ,
0 commit comments