1010using CounterStrikeSharp . API . Core . Plugin ;
1111
1212namespace CustomCommands . Services ;
13- public class ReplaceTagsFunctions : IReplaceTagsFunctions
13+ public partial class ReplaceTagsFunctions : IReplaceTagsFunctions
1414{
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 ;
1818
1919 public ReplaceTagsFunctions ( IPluginGlobals PluginGlobals , IPluginContext PluginContext ,
2020 ILogger < CustomCommands > Logger )
2121 {
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 ;
2525 }
2626
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>
3527 public string [ ] ReplaceTags ( dynamic input , CCSPlayerController player )
3628 {
37- List < string > output = WrappedLine ( input ) ;
29+ var output = WrappedLine ( input ) ;
3830
3931 for ( int i = 0 ; i < output . Count ; i ++ )
4032 output [ i ] = ReplaceLanguageTags ( output [ i ] ) ;
@@ -44,58 +36,102 @@ public string[] ReplaceTags(dynamic input, CCSPlayerController player)
4436 for ( int i = 0 ; i < output . Count ; i ++ )
4537 {
4638 output [ i ] = ReplaceMessageTags ( output [ i ] , player , false ) ;
39+ output [ i ] = ReplaceRandomTags ( output [ i ] ) ;
4740 output [ i ] = ReplaceColorTags ( output [ i ] ) ;
4841 }
4942
50- return output . ToArray < string > ( ) ;
43+ return output . ToArray ( ) ;
5144 }
5245
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+
6149 public string ReplaceLanguageTags ( string input )
6250 {
63- CustomCommands plugin = ( PluginContext . Plugin as CustomCommands ) ! ;
64-
65- // Define the regex pattern to find "{LANG=...}"
66- string pattern = @"\{LANG=(.*?)\}" ;
67-
6851 // Use Regex to find matches
69- Match match = Regex . Match ( input , pattern ) ;
52+ var match = ReplaceLanguageTagsRegex ( ) . Match ( input ) ;
7053
7154 // Check if a match is found
7255 if ( match . Success )
7356 {
7457 // 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>" ) ;
7762 }
7863 else
7964 {
8065 // Return the original string if no match is found
8166 return input ;
8267 }
8368 }
84-
69+
8570 /// <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}}
8772 /// </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+
92128 public string ReplaceMessageTags ( string input , CCSPlayerController player , bool safety = true )
93129 {
94- SteamID steamId = new SteamID ( player . SteamID ) ;
130+ var steamId = new SteamID ( player . SteamID ) ;
95131
96132 Dictionary < string , string > replacements = new ( )
97133 {
98- { "{PREFIX}" , PluginGlobals . Config . Prefix ?? "<PREFIX not found>" } ,
134+ { "{PREFIX}" , _pluginGlobals . Config . Prefix ?? "<PREFIX not found>" } ,
99135 { "{MAP}" , NativeAPI . GetMapName ( ) ?? "<MAP not found>" } ,
100136 { "{TIME}" , DateTime . Now . ToString ( "HH:mm:ss" ) ?? "<TIME not found>" } ,
101137 { "{DATE}" , DateTime . Now . ToString ( "dd.MM.yyyy" ) ?? "<DATE not found>" } ,
@@ -109,7 +145,7 @@ public string ReplaceMessageTags(string input, CCSPlayerController player, bool
109145 { "{PORT}" , ConVar . Find ( "hostport" ) ! . GetPrimitiveValue < int > ( ) . ToString ( ) ?? "<PORT not found>" } ,
110146 { "{MAXPLAYERS}" , Server . MaxPlayers . ToString ( ) ?? "<MAXPLAYERS not found>" } ,
111147 { "{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>" } ,
113149 } ;
114150
115151 // Prevent vounrability by not replacing {PLAYERNAME} if safety is true/ServerCommands are being executed
@@ -155,46 +191,41 @@ public string ReplaceColorTags(string input)
155191 return input ;
156192 }
157193
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>
163194 public List < string > WrappedLine ( dynamic input )
164195 {
165- List < string > output = new List < string > ( ) ;
196+ var output = new List < string > ( ) ;
166197
167198 if ( input is JsonElement jsonElement )
168199 {
169200 switch ( jsonElement . ValueKind )
170201 {
171202 case JsonValueKind . String :
172- string result = jsonElement . GetString ( ) ! ;
203+ var result = jsonElement . GetString ( ) ! ;
173204 output . AddRange ( result . Split ( new [ ] { "\r \n " , "\r " , "\n " } , StringSplitOptions . None ) ) ;
174205 break ;
175206 case JsonValueKind . Array :
176207 foreach ( var arrayElement in jsonElement . EnumerateArray ( ) )
177208 {
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 > ( ) ;
179210 output . AddRange ( lines ) ;
180211 }
181212 break ;
182213
183214 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") ;
185216 break ;
186217 }
187218 } else if ( input is Array inputArray )
188219 {
189220 foreach ( string arrayElement in inputArray )
190221 {
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 > ( ) ;
192223 output . AddRange ( lines ) ;
193224 }
194225 }
195226 else
196227 {
197- Logger . LogError ( $ "{ PluginGlobals . Config . LogPrefix } Invalid input type") ;
228+ _logger . LogError ( $ "{ _pluginGlobals . Config . LogPrefix } Invalid input type") ;
198229 }
199230
200231 return output ;
@@ -206,9 +237,9 @@ public List<string> WrappedLine(dynamic input)
206237 /// </summary>
207238 /// <param name="input"></param>
208239 /// <returns></returns>
209- private string PadLeftColorTag ( string input )
240+ private static string PadLeftColorTag ( string input )
210241 {
211- string [ ] colorTagList = new string [ ] {
242+ var colorTagList = new string [ ] {
212243 "{DEFAULT}" ,
213244 "{WHITE}" ,
214245 "{DARKRED}" ,
0 commit comments