-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchat_cmds_multi.txt
1648 lines (1341 loc) · 56.3 KB
/
chat_cmds_multi.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--@name Chat Cmds Multi
--@author legokidlogan
--@shared
--@include lkl/easy_print.txt
--@include lkl/cl_check_permissions.txt
--@include lkl/bulletlist.txt
--[[
- An overhaul of my chat_cmds library, designed to support multiple instances per starfall chip.
- Usage is roughly similar, with some key differences:
- For each project with its own set of chat commands, you must first register it using ccmdMulti.registerProject().
- All library functions now have cmdPrefix as a new and first argument, with one exception:
- ccmdMulti.processCommand():
- old: ( ply, cmdName, argsIn, hideCommandPrinting )
- new: ( ply, cmdPrefix, cmdName, argsIn, hideCommandPrinting )
- Some library functions have paramters which can be given as functions. Of those paramters, the following have changed their arguments:
- filterNewJoinsFunc:
- old: ( ply )
- new: ( ply, cmdPrefix )
- targetsOverride:
- old: ( cmdName, ply )
- new: ( cmdPrefix, cmdName, ply )
- cmdFunc:
- old: ( cmdName, callingPly, argsAsString, cmdVarArgs )
- new: ( cmdPrefix, cmdName, callingPly, argsAsString, cmdVarArgs )
- failCasesFunc:
- old: ( cmdName, callingPly, argsAsString, cmdVarArgs )
- new: ( cmdPrefix, cmdName, callingPly, argsAsString, cmdVarArgs )
- argInfo:
- old: ( cmdName, callingPly )
- new: ( cmdPrefix, cmdName, callingPly )
- helpInfo:
- old: ( cmdName, callingPly, cmdVarArgs )
- new: ( cmdPrefix, cmdName, callingPly, cmdVarArgs )
--]]
ccmdMulti = ccmdMulti or {}
if ccmdMulti._alreadyLoaded then return end
ccmdMulti._alreadyLoaded = true
ccmdMulti.filters = ccmdMulti.filters or {}
require( "lkl/bulletlist.txt" )
local epScheme = require( "lkl/easy_print.txt" )
local ep = easyPrint
ccmdScheme = ColorScheme.createIfNew( "ChatCmds", epScheme, nil, nil )
if CLIENT then
local function tableInsertUnique( tbl, val )
if table.hasValue( tbl, val ) then return end
table.insert( tbl, val )
end
permissions = permissions or {}
permissionSatisfied = permissionSatisfied or false
permissionRequestSent = permissionRequestSent or false
tableInsertUnique( permissions, "print.chat" )
tableInsertUnique( permissions, "print.console" )
tableInsertUnique( permissions, "print.color" )
if not setupPermissionRequestSafe then
require( "lkl/cl_check_permissions.txt" )
setupPermissionRequestSafe( permissions, "Use chat commands", true )
timer.simple( 1, function()
checkPermissions()
end )
end
return
end
local cmdPrefixToProject = {}
local preprocessedResults = nil
local visIfAvailCurrentlyChecking = false
local stateStrVals = {
["1"] = true,
["enabled"] = true,
["enable"] = true,
["on"] = true,
["true"] = true,
["0"] = false,
["disabled"] = false,
["disable"] = false,
["off"] = false,
["false"] = false,
}
local reservedCommands = {
help = true,
commands = true,
}
local tableIsEmpty = table.isEmpty
local tableRemove = table.remove
local tableInsert = table.insert
local tableAdd = table.add
local tableConcat = table.concat
local stringGsub = string.gsub
local stringSub = string.sub
local stringLen = string.len
local stringExplode = string.explode
local mMax = math.max
local makePlayerLookup
local removeSpaces
local makeArgInfo
local printToPly
local processCommand
local registerReservedCommands
ccmdMulti._cmdPrefixToProject = cmdPrefixToProject
----- GLOBAL FUNCTIONS -----
--[[
- Register a project for you to then make chat commands under.
- cmdPrefix will be used as the main identifier for the project in other library functions.
cmdPrefix: (string)
- The command prefix which will be used to call commands from this project.
- Case-sensitive. It's recommended to use all lowercase.
- All projects must have different command prefixes.
- ex: "/cam"
projectName: (string)
- The name of the project.
- Must be distinct from all other projects.
- ex: "Camera" results in project prints starting out with "[Camera] "
options: (table) (optional)
- Additional options for the project.
{
PrintCommands = (boolean)
- Should the original command message be printed to the player's chat before running it?
- Default: true
UsePCall = (boolean)
- Should chat command functions be wrapped in a pcall?
- If so, unsuccessful calls will have their error message printed out instead of erroring the chip.
- Default: true
}
--]]
function ccmdMulti.registerProject( cmdPrefix, projectName, options )
if type( cmdPrefix ) ~= "string" then error( "Expected cmdPrefix to be a string" ) end
if cmdPrefixToProject[cmdPrefix] then error( "A project is already registered with the cmdPrefix of \"" .. cmdPrefix .. "\"" ) end
if string.find( cmdPrefix, "[%s%c]" ) then error( "cmdPrefix cannot contain whitespace or control characters" ) end
if type( projectName ) ~= "string" then error( "Expected projectName to be a string" ) end
for _, project in pairs( cmdPrefixToProject ) do
if project.ProjectName == projectName then error( "A project is already registered with the name \"" .. projectName .. "\"" ) end
end
options = options or {}
local printCommands = options.PrintCommands
local usePCall = options.UsePCall
if printCommands == nil then printCommands = true end
if usePCall == nil then usePCall = true end
cmdPrefixToProject[cmdPrefix] = {
ProjectName = projectName,
PrintCommands = printCommands,
UsePCall = usePCall,
Commands = {},
Aliases = {},
Targets = {},
TargetNewJoinsFilter = function() return end,
CmdPrefixLength = #cmdPrefix,
PrintName = "[" .. projectName .. "]",
}
registerReservedCommands( cmdPrefix )
end
--[[
- Gets the info of a command within a project.
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string)
- The name of the command to get info for.
- If this is an alias, it will return the info for the main command,
along with a second return value of the main command's name.
RETURNS: cmdInfo, mainCmdName
cmdInfo: (table)
- The command's info. It's best if you don't modify any of this directly.
- Further details can be found in the documentation for ccmdMulti.createCommand().
{
Func = cmdFunc,
FailCasesFunc = failCasesFunc,
ArgInfo = argInfo,
HelpInfo = helpInfo,
TargetsOverride = targetsOverride,
NewJoinsFunc = filterNewJoinsFunc,
-- If this command has aliases:
Aliases = aliasNames,
AliasCount = alianCount,
}
mainCmdName: (nil or string)
- Name of main command, if cmdName is an alias.
--]]
function ccmdMulti.getCommandInfo( cmdPrefix, cmdName )
local project = cmdPrefixToProject[cmdPrefix]
local commands = project.Commands
cmdName = cmdName or ""
local cmdInfo = commands[cmdName]
if cmdInfo then return cmdInfo end
local mainCmdName = project.Aliases[cmdName]
if mainCmdName then return commands[mainCmdName], mainCmdName end
end
--[[
- Decides who can and cannot use a project's chat commands.
- Each command can have its own override which bypasses this.
cmdPrefix: (string)
- The command prefix of the project.
plys:
- { plyOne, plyTwo, plyThree, ... } -> Sets these players as the new targets to allow chat commands from.
- Either numerically indexed, or a lookup table (i.e. { [1] = plyOne, [2] = plyTwo, ... } or { [plyOne] = tue, [plyTwo] = true, ... })
- {} / false -> Do not target any players.
- ply -> Target one specific player. Same as { ply }
- nil -> Target ALL players.
filterNewJoinsFunc: (optional) (bool or function)
- BOOL:
- If true, will always add new joins to the target list.
- If false/nil, will never add new joins to the target list.
- FUNCTION: function( ply, cmdPrefix ) return canAddPlyToTargetList end
- canAddPlyToTargetList: (bool)
--]]
function ccmdMulti.setTargets( cmdPrefix, plys, filterNewJoinsFunc )
local project = cmdPrefixToProject[cmdPrefix]
project.Targets = makePlayerLookup( plys ) or project.Targets
if type( filterNewJoinsFunc ) ~= "function" then
if filterNewJoinsFunc then
filterNewJoinsFunc = function() return true end
else
filterNewJoinsFunc = function() return false end
end
end
project.TargetNewJoinsFilter = filterNewJoinsFunc
end
--[[
- Change the override for who can see a particular command.
- Similar parameter behavior to ccmdMulti.setTargets(), except for the following differences:
cmdPrefix: (string)
- The command prefix of the project.
plys:
- If nil, will remove override entirely.
filterNewJoinsFunc: (nil, bool, or function)
- NIL:
- Will retain previous filter function.
- BOOL:
- If true, will always add new joins to the target override list.
- If false, will never add new joins to the target override list.
- FUNCTION: function( ply, cmdPrefix, cmdName ) return canAddPlyToTargetList end
- canAddPlyToTargetList: (bool)
--]]
function ccmdMulti.setTargetsForCommand( cmdPrefix, cmdName, plys, filterNewJoinsFunc )
local cmdInfo, mainCmdName = ccmdMulti.getCommandInfo( cmdPrefix, cmdName )
if not cmdInfo then
error( "There is no command registered with the name \"" .. tostring( cmdName ) .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
if reservedCommands[mainCmdName or cmdName] then
error( "\"" .. tostring( mainCmdName or cmdName ) .. "\" is a reserved command and cannot be modified" )
end
if plys == nil then
cmdInfo.TargetsOverride = nil
cmdInfo.NewJoinsFunc = nil
return
end
if filterNewJoinsFunc == nil then
filterNewJoinsFunc = cmdInfo.NewJoinsFunc
end
if filterNewJoinsFunc ~= nil and type( filterNewJoinsFunc ) ~= "function" then
if type( filterNewJoinsFunc ) ~= "boolean" then
error( "Expected filterNewJoinsFunc to be nil, a boolean, or a function" )
end
if filterNewJoinsFunc then
filterNewJoinsFunc = function() return true end
else
filterNewJoinsFunc = function() return false end
end
end
if type( plys ) == "function" then
cmdInfo.TargetsOverride = plys
else
cmdInfo.TargetsOverride = makePlayerLookup( plys ) or cmdInfo.TargetsOverride
end
if type( cmdInfo.TargetsOverride == "function" ) then
filterNewJoinsFunc = nil
end
cmdInfo.NewJoinsFunc = filterNewJoinsFunc
end
--[[
- Returns whether or not a given player can see a command.
cmdPrefix: (string)
- The command prefix of the project.
ply: (player)
- The player to check.
cmdName: (nil or string)
NIL:
- Checks the global target list.
STRING:
- Checks that command's target override list, or the global list if there is no override.
ignoreCommandValidity: (optional) (bool)
- If true, will return false instead of an error if cmdName is not a registered command.
RETURNS: canSee
canSee: (bool)
- Can the player see this command?
- Does not check for the player's ability to *run* the command, only the ability to see it.
--]]
function ccmdMulti.canSeeCommand( cmdPrefix, ply, cmdName, ignoreCommandValidity )
if not isValid( ply ) or not ply:isPlayer() then
error( "You must provide a valid player" )
end
local project = cmdPrefixToProject[cmdPrefix]
if cmdName == nil then
return project.Targets[ply] == true
end
local cmdInfo = ccmdMulti.getCommandInfo( cmdPrefix, cmdName )
if not cmdInfo then
if ignoreCommandValidity then return false end
error( "There is no command registered with the name \"" .. tostring( cmdName ) .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
local targetsOverride = cmdInfo.TargetsOverride
if targetsOverride then
if type( targetsOverride ) == "function" then
return targetsOverride( cmdPrefix, cmdName, ply )
end
return targetsOverride[ply] == true
end
return project.Targets[ply] == true
end
--[[
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string or table)
- The name of the command, cannot include whitespace (e.g. space, newline, tab)
- STRING:
- Just a string.
- TABLE:
- A list of strings, where the first entry is the main command name, and the rest are aliases.
- An alias is simply an alternate name to call a command with, such as having a 'teleport' command as well as its alias, 'tp'
- If you modify a command (e.g. with ccmdMulti.setTargetsForCommand()), it will also alter its aliases, and vice versa.
- Alias names will be shown next to their main name in places like '/myPrefix cmds' and '/myPrefix help mainCmdName'
cmdFunc: (function or string)
- FUNCTION: function( cmdPrefix, cmdName, callingPly, argsAsString, cmdVarArgs ) return returnVal1, returnVal2 end
- argsAsString: The player's arguments, appended together as a single string.
- For example, the chat message "/myPrefix cmdName arg1 arg2" yields "arg1 arg2"
- cmdVarArgs: The variable arguments provided by the player.
- For example, the chat message "/myPrefix cmdName arg1 arg2" yields ( "arg1", "arg2" )
- Again, these are var-args, not a single table arg.
- returnVal1: (nil, bool, string, or table)
- BOOL:
- Doesn't print to chat (regardless of true/false), same as returning nil.
- Use this if you have UsePCall set to true and need to alter the player's chat message (via returnVal2).
- Starfall pcall loses return values that come after the first nil, so you need this to retain returnVal2 under those circumstances.
- STRING: This will be printed to callingPly's chat in white text.
- TABLE: { COLOR, STRING, COLOR, STRING, ... }
- Colored text to print to callingPly's chat.
- Your message will automatically get prepended by 'printName .. " "' in white text, for consistency and identification.
- printName is determined by the project upon registration in ccmdMulti.registerProject().
- returnVal2: (nil or string)
- STRING: Replaces the player's chat message with this, instead of just hiding the message.
- The function for the command to call.
- If applicable, will only get called after the command successfully passes through failCasesFunc.
- STRING:
- Name of command to become an alias of.
- IMPORTANT: If provided as a string, this will be marked as an alias. All other arguments will be ignored.
failCasesFunc: (optional) (function)
- Has the form function( cmdPrefix, cmdName, callingPly, argsAsString, cmdVarArgs ) return failMessage, badArgInd end
- failMessage: (nil, string, or table)
- NIL:
- No preemptive failure has been found. The chat command will run.
- STRING:
- A simple failure message, colored red.
- TABLE: { COLOR, STRING, COLOR, STRING, ... }
- Allows for colored text.
- badArgInd: (optional) (integer > 0)
- The numerical index of the cmdVarArgs param that caused the failure, if applicable.
- If failMessage is nil, then badArgInd can instead be any type, and will be retrievable in cmdFunc via ccmdMulti.getPreprocessedResults().
- This is a way to reduce redundant processing on successfull commands.
- See ccmdMulti.getPreprocessedResults() for more info and an example.
- Lets you have nicely-formatted misuse/invalid arg cases, with relevant info being printed out.
- This runs before cmdFunc, so this is to check command availability and do input sanitization, not handle execution errors.
- The player not providing all required args will be auto-checked before failCasesFunc.
- This is based on argInfo, which assumes the required arg count doesn't change (other than per-player differences, if applicable).
- If you have extra required args that dynamically exist based on other arguments, you must handle it in failCasesFunc, not argInfo.
- The player being marked as 'not a target' for the command is auto-checked first as well.
- If the player isn't on the list, they simply won't see this command.
- You can use failCasesFunc for having always-visible commands that just say 'you don't have access to use this', etc.
argInfo: (optional) (table or function)
- Provides info about the command's chat arguments.
- If nil, will assume all args are required, give them generic names, and will try to auto-calculate cmdFunc's param count.
- TABLE:
{
ReqCount = NUMBER, -- The number of required arguments, which all come first in the command.
OptCount = NUMBER, -- The number of optional arguments, which all come after the required ones. If you have more names than RC + OC, the extras are assumed to be optional args.
[1] = {
Name = STRING, -- Name of the first argument, defaults to "arg1"
Description = STRING OR TABLE or BULLETLIST,
-- Description of the first argument.
-- Can be a string, a table of strings (each string is a new line), a table of printTbls (each printTbl is a new line), or a BulletList.
-- printTbls are sequential tables that alternate between color and string.
},
[2] = {
Name = STRING,
Descriptiopn = STRING OR TABLE,
},
[3] = {
Name = STRING,
Descriptiopn = STRING OR TABLE,
},
...
}
- FUNCTION: function( cmdPrefix, cmdName, callingPly ) return returnVal end
- returnVal: (table)
- Same format as the TABLE version of argInfo.
helpInfo: (optional) (string, table, or function)
- Provides additional help text for use with "/myPrefix help cmdName"
- Note that the help command automatically includes argInfo, so you don't need to worry about printing it here.
- STRING:
- A simple one-line description for the command, nothing fancy.
- TABLE:
{
[1] = STRING OR TABLE, -- The first line of help text. Can either be a string or a printTbl (sequential table that alternates between color and string).
[2] = STRING OR TABLE, -- The second line of help text.
...
}
- Allows for colored text.
- Each line will be on its own bullet point.
- FUNCTION: function( cmdPrefix, cmdName, callingPly, cmdVarArgs ) return returnVal end
- cmdVarArgs: Additional varargs from the player, for adding extra-specific help requests.
- e.g. "/myPrefix help cmdName arg1 arg2" yields ( "arg1", "arg2" )
- returnVal: (table)
- Same format as the TABLE version of helpInfo.
- If you have a complex enough command to need this as a function and go through the trouble of making it,
please make sure to include info about your special 'help args' in the default case where the player gives no args.
targetsOverride: (optional) (player, table, or function)
- Determines who can and can't use this command, regardless of whatever has been set globally with ccmdMulti.setTargets().
- If a player is on the global target list, but not the override, they will receive a print saying the command doesn't exist.
- If you want to let the player see the command, but not have access to running it, you should make use of failCasesFunc.
- If a player is missing from both lists, they will simply never get a print.
- PLAYER/TABLE:
- Same expectations and behavior as ccmdMulti.setTargets().
- Note that nil and false are not available options!
- To target all players, provide find.allPlayers().
- To target nobody, provide {}
- You can change this later with ccmdMulti.setTargetsForCommand().
- This list may or may not get modified later when players join, depending on filterNewJoinsFunc.
- FUNCTION: function( cmdPrefix, cmdName, callingPly ) return returnVal end
- returnVal: (bool)
- Can the player see this function?
- If targetsOverride is given as a function, it will update visibility any time the command might attempt to be seen or ran.
- It will also cause filterNewJoinsFunc to be obsolete.
filterNewJoinsFunc: (optional) (bool or function)
- Behaves the same way as it does in ccmdMulti.setTargetsForCommand().
- To minimize on networking, wherever there's a COLOR for print formatting in the above definitions,
you can alternatively use the string "::c_SOMECOLORNAME" with the colors defined in gcolors.txt
--]]
function ccmdMulti.createCommand( cmdPrefix, cmdName, cmdFunc, failCasesFunc, argInfo, helpInfo, targetsOverride, filterNewJoinsFunc )
local project = cmdPrefixToProject[cmdPrefix]
if not cmdName then
error( "You must provide a valid chat command name" )
end
if type( cmdName ) == "table" then
local mainCmdName = cmdName[1]
ccmdMulti.createCommand( cmdPrefix, mainCmdName, cmdFunc, failCasesFunc, argInfo, helpInfo, targetsOverride, filterNewJoinsFunc )
for i = 2, #cmdName do
ccmdMulti.createCommand( cmdPrefix, cmdName[i], mainCmdName )
end
return
end
if type( cmdName ) ~= "string" then
error( "Expected cmdName to be a string or a table" )
end
local projectCommands = project.Commands
local projectAliases = project.Aliases
cmdName = removeSpaces( cmdName, "" )
if cmdName == "" then
error( "You must provide a valid chat command name" )
end
if projectCommands[cmdName] then
error( "There is already a chat command registered with the name \"" .. cmdName .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
if type( cmdFunc ) == "string" then
local mainCmdName = projectAliases[cmdFunc] or cmdFunc -- Get the original command if cmdFunc is itself another alias
local cmdInfo = projectCommands[mainCmdName]
if not cmdInfo then
error( "Couldn't find a chat command registered with the name \"" .. mainCmdName .. "\" to make an alias \"" .. cmdName .. "\" from, while under cmdPrefix \"" .. cmdPrefix .. "\"" )
end
local aliases = cmdInfo.Aliases
local aliasCount = cmdInfo.AliasCount
projectAliases[cmdName] = mainCmdName
if not aliases then
aliases = {}
aliasCount = 0
cmdInfo.Aliases = aliases
end
aliasCount = aliasCount + 1
aliases[aliasCount] = cmdName
cmdInfo.AliasCount = aliasCount
return
end
if type( cmdFunc ) ~= "function" then
error( "You must provide a valid chat command function" )
end
if failCasesFunc ~= nil and type( failCasesFunc ) ~= "function" then
error( "Expected failCasesFunc to be nil or a function" )
end
if type( argInfo ) ~= "function" then
if type( argInfo ) == "table" then
argInfo.__IsValidated = false
end
argInfo = makeArgInfo( argInfo, cmdFunc, cmdPrefix, cmdName )
end
if helpInfo ~= nil and type( helpInfo ) ~= "string" and type( helpInfo ) ~= "table" and type( helpInfo ) ~= "function" then
error( "Expected helpInfo to be nil, a string, a table, or a function" )
end
if targetsOverride then
if type( targetsOverride ) == "function" then
filterNewJoinsFunc = nil
else
targetsOverride = makePlayerLookup( targetsOverride )
if not targetsOverride then
error( "Expected targetsOverride to be nil, a player, a table, or a function" )
end
end
end
if filterNewJoinsFunc ~= nil then
if type( filterNewJoinsFunc ) == "boolean" then
if filterNewJoinsFunc then
filterNewJoinsFunc = function() return true end
else
filterNewJoinsFunc = function() return false end
end
elseif type( filterNewJoinsFunc ) ~= "function" then
error( "Expected filterNewJoinsFunc to be nil, a boolean, or a function" )
end
end
projectCommands[cmdName] = {
Name = cmdName,
Func = cmdFunc,
FailCasesFunc = failCasesFunc,
ArgInfo = argInfo,
HelpInfo = helpInfo,
TargetsOverride = targetsOverride,
NewJoinsFunc = filterNewJoinsFunc,
}
end
--[[
A quick and easy way to create a chat command that toggles/sets a flag between off and on.
Make sure to store the functions returned by this, as they are required to get the flag's current value,
unless you track it yourself in stateCallback().
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string or table)
- Same as in ccmdMulti.createCommand().
stateCallback: (optional) (function)
- FUNCTION: function( oldState, newState, ply ) return overrideState end
- ply: (player or nil)
- The player who ran the command.
- overrideState: (optional) (bool)
- Will override the state, used for preventing changes under certain conditions.
- Gets called automatically by stateSetter() so you can perform actions whenever your flag changes or double-sets.
- Note that players can provide an optional chat argument to set the state directly to on/off instead of toggling.
valueName: (optional) (string)
- The display name for your flag, used in the resulting chat message: valueName .. " is now " .. [enabled/disabled] .. "."
- Defaults to the primary name in cmdName.
description: (optional) (string)
- The short description used in the command's help info, which will say "Enables/disables " .. description .. "."
- Defaults to valueName.
initialState: (optional) (bool)
- The initial value of your flag.
targetsOverride: (optional) (player or table)
- Same as in ccmdMulti.createCommand().
filterNewJoinsFunc: (optional) (bool or function)
- Same as in ccmdMulti.setTargetsForCommand().
RETURNS: stateSetter, stateGetter
stateSetter: (function)
- FUNCTION: function( state, ply ) return end
- Calls stateCallback() and sets the value of your flag accordingly.
- ply is optional, and gets passed to stateCallback().
stateGetter: (function)
- FUNCTION: function() return state end
- Gives the current value of your flag.
--]]
function ccmdMulti.createToggleCommand( cmdPrefix, cmdName, stateCallback, valueName, description, initialState, targetsOverride, filterNewJoinsFunc )
local mainCmdName
cmdName = cmdName or ""
if type( cmdName ) == "string" then
cmdName = removeSpaces( cmdName, "" )
end
if cmdName == "" or ( type( cmdName ) ~= "string" and type( cmdName ) ~= "table" ) then
error( "You must provide a valid chat command name" )
end
local project = cmdPrefixToProject[cmdPrefix]
local projectCommands = project.Commands
if type( cmdName ) == "string" then
if projectCommands[cmdName] then
error( "There is already a chat command registered with the name \"" .. cmdName .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
mainCmdName = cmdName
else
for _, alias in ipairs( cmdName ) do
if projectCommands[alias] then
error( "There is already a chat command registered with the name \"" .. alias .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
end
mainCmdName = cmdName[1]
end
if type( initialState ) ~= "boolean" then
initialState = false
end
if type( stateCallback ) ~= "function" then
stateCallback = function() end
end
local stateFlag = initialState
valueName = valueName or mainCmdName
description = description or valueName
if type( valueName ) ~= "string" then
error( "Expected valueName to be nil or a string" )
end
if type( description ) ~= "string" then
error( "Expected description to be nil or a string" )
end
local cText = ccmdScheme:getColor( "Text" )
local cHighlight = ccmdScheme:getColor( "Highlight" )
local cTrue = ccmdScheme:getColor( "true" )
local cFalse = ccmdScheme:getColor( "false" )
local function stateSetter( state, ply )
local overrideState = stateCallback( stateFlag, state, ply )
if overrideState == nil then
stateFlag = state
else
stateFlag = overrideState
end
end
local function stateGetter()
return stateFlag
end
local function cmdFunc( _, _, ply, _, stateStr )
local state = stateStrVals[stateStr]
if state == nil then
state = not stateFlag
end
stateSetter( state, ply )
return {
cText, valueName .. " is now ",
state and cTrue or cFalse, state and "enabled" or "disabled",
cText, "."
}
end
local function failCasesFunc()
return -- No fail cases
end
local argInfo = {
ReqCount = 0,
OptCount = 1,
{
Name = "state",
Description = {
{
cText, "Sets the state directly, instead of toggling.",
},
{
cText, "Can be ",
cTrue, "on",
cText, ", ",
cFalse, "off",
cText, ", ",
cTrue, "1",
cText, ", ",
cFalse, "0",
cText, ", etc.",
},
},
},
}
local helpInfo = {
{
cText, "Enables/disables ",
cHighlight, description,
cText, "."
},
}
ccmdMulti.createCommand( cmdPrefix, cmdName, cmdFunc, failCasesFunc, argInfo, helpInfo, targetsOverride, filterNewJoinsFunc )
return stateSetter, stateGetter
end
--[[
- Removes a command or alias so that it may be re-registered later with different functionality.
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string)
- The name of the command to remove.
- If the command has aliases, those will be removed as well.
- If cmdName is itself an alias, then only that one alias will be removed.
--]]
function ccmdMulti.removeCommand( cmdPrefix, cmdName )
if type( cmdName ) ~= "string" then
error( "Expected cmdName to be a string" )
end
local cmdInfo, mainCmdName = ccmdMulti.getCommandInfo( cmdPrefix, cmdName )
if not cmdInfo then
error( "There is no command registered with the name \"" .. cmdName .. "\" for cmdPrefix \"" .. cmdPrefix .. "\"" )
end
if reservedCommands[mainCmdName or cmdName] then
error( "\"" .. tostring( mainCmdName or cmdName ) .. "\" is a reserved command and cannot be removed" )
end
local project = cmdPrefixToProject[cmdPrefix]
local projectCommands = project.Commands
local projectAliases = project.Aliases
if mainCmdName then -- Only removing a single alias
local aliasCount = cmdInfo.AliasCount - 1
projectAliases[cmdName] = nil
if aliasCount == 0 then
cmdInfo.Aliases = nil
cmdInfo.AliasCount = nil
return
end
cmdInfo.AliasCount = aliasCount
table.removeByValue( cmdInfo.Aliases, cmdName )
return
end
local aliases = cmdInfo.Aliases
if aliases then -- Command has aliases to remove
for i = 1, cmdInfo.AliasCount do
local alias = aliases[i]
projectAliases[alias] = nil
end
end
projectCommands[cmdName] = nil
end
--[[
- During execution of cmdFunc in a chat command, this will give the second return value of failCasesFunc.
- This is useful if cmdFun and failCasesFunc repeat the same portion of argument processing.
Example:
ccmdMulti.createCommand(
"/myPrefix",
"slap",
function( _, _, _, argsAsString )
local targetPly = ccmdMulti.getPreprocessedResults()
slap( targetPly )
end,
function( _, _, _, argsAsString )
local targetPly = find.playersByName( argsAsString )[1]
if not isValid( targetPly ) then
return {
ccmdScheme:getColor( "Fail" ), "Couldn't find a player by the name of ",
ccmdScheme:getColor( "Highlight" ), argsAsString,
}, 0
end
return nil, targetPly
end,
{
ReqCount = 1,
OptCount = 0,
{
Name = "target",
Description = "The player to slap.",
},
},
"Slaps a player.",
owner(),
false
)
--]]
function ccmdMulti.getPreprocessedResults()
return preprocessedResults
end
--[[
- Process a command directly.
- Useful for automation and shortcuts like "/tp someGuy" --> "/myPrefix tp someGuy" without needing chat re-send delays.
ply: (entity)
- The player who would be running this command.
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string)
- The name of the command to run.
argsIn: (table or string)
- Command arguments, either as a numerical table or space-separated string.
hideCommandPrinting: (bool)
- If true, will forcefully prevent the command call from getting echoed to the player's chat
RETURNS: chatOverride
chatOverride: (string)
- A string to override the player's original message with, for use with the PlayerSay hook.
--]]
function ccmdMulti.processCommand( ply, cmdPrefix, cmdName, argsIn, hideCommandPrinting )
local argsAsString
local args
if argsIn == nil then
argsIn = {}
end
if type( argsIn ) == "string" then
argsAsString = argsIn
args = stringExplode( " ", argsAsString )
elseif type( argsIn ) == "table" then
args = argsIn
argsAsString = tableConcat( args, " " )
else
error( "Expected argsIn to be a string or a table" )
end
local argCount = #args
local msg = cmdPrefix .. " " .. cmdName
if argCount > 0 then
msg = msg .. " " .. argsAsString
end
return processCommand( ply, msg, cmdPrefix, cmdName, args, argsAsString, hideCommandPrinting )
end
--[[
- Manually prints a chat command fail message to chat.
- For use if there's something that could halt a chat command but cannot be checked with failCasesFunc.
- e.g. commands that occur over time, or where the action and its validity check cannot be separated.
cmdPrefix: (string)
- The command prefix of the project.
cmdName: (string)
- The name of the command that failed.
ply: (player)
- The player who tried to run the command.
msg: (string)
- The player's chat message.
failMsg: (string or table)
- The message to print to the player's chat.
- STRING: A simple failure message, colored red.
- TABLE: { COLOR, STRING, COLOR, STRING, ... }
- Allows for colored text.
badArgInd: (optional) (integer > 0)
- The numerical index of the cmdVarArgs param that caused the failure, if applicable.
...: (optional) (string varargs)
- The arguments used in the command.
--]]
function ccmdMulti.printFailCase( cmdPrefix, cmdName, ply, msg, failMsg, badArgInd, ... )
local args = { ... }
local project = cmdPrefixToProject[cmdPrefix]
badArgInd = badArgInd or 0
local cHighlight = ccmdScheme:getColor( "Highlight" )
local cHighlightWeak = ccmdScheme:getColor( "HighlightWeak" )
local cFail = ccmdScheme:getColor( "Fail" )
local cBulletPoint = ccmdScheme:getColor( "BulletPoint" )
local printTbl = ep.chipNamePrefix( ccmdScheme, project.PrintName )
tableAdd( printTbl, {
cFail, "Command failed: ",
} )
msg = stringSub( msg, project.CmdPrefixLength + 1 + stringLen( cmdName ) + 2 ) or ""
tableInsert( printTbl, cHighlightWeak )
tableInsert( printTbl, cmdPrefix .. " " .. cmdName .. " " )
if badArgInd > 0 then
local argCount = #args
for i = 1, argCount do
if i == badArgInd then
tableInsert( printTbl, cFail )
else
tableInsert( printTbl, cHighlight )
end
if i == argCount then
tableInsert( printTbl, args[i] )
else
tableInsert( printTbl, args[i] .. " " )
end