|
64 | 64 | logDir = srvrFolder+'RunServerDotPy/Logs/' # ./RunServerDotPy/Logs/ |
65 | 65 | totalLogDir = logDir+'Total/' # ./RunServerDotPy/Logs/Total/ |
66 | 66 | cacheDir = srvrFolder+'RunServerDotPy/Cache/' # ./RunServerDotPy/Cache/ |
| 67 | +modDir = srvrFolder+'RunServerDotPy/Mods/' # ./RunServerDotPy/Mods/ |
67 | 68 |
|
68 | 69 | # Fix main RunServerDotPy directory if missing |
69 | 70 | if not os.path.exists(srvrFolder+'RunServerDotPy'): os.mkdir(srvrFolder+'RunServerDotPy') |
@@ -461,7 +462,7 @@ def parseOutput(line): #Parses the output, running subfunctions for logging and |
461 | 462 | logData('"'+chatL[1]+'" tried to run "'+chatL[2]+'"', 'ChatCommands') |
462 | 463 | parseChatCommand(chatL[1], chatL[2]) |
463 | 464 | elif chatL[0] == 2: logData('"'+chatL[1]+'" /me\'d "'+chatL[2]+'"', 'Chat') #Is a /me message, save it in the chat log formatted like: "[User]" /me'd "[Message]" |
464 | | - elif chatL[0] == 3: logData('"'+chatL[1]+'" /said "'+chatL[2]+'"', 'Chat') #Is a /say message, save it in the chat log formatted like: "[User]" /said "[Message]" |
| 465 | + elif (chatL[0] == 3) and (not chatL[1] == 'Server'): logData('"'+chatL[1]+'" /said "'+chatL[2]+'"', 'Chat') #Is a /say message, save it in the chat log formatted like: "[User]" /said "[Message]" |
465 | 466 | if profanity.contains_profanity(chatL[1]): #Chat message potentially contains profanity, warn user and log it |
466 | 467 | tellRaw('<'+chatL[0]+'> '+profanity.censor(chatL[1], '!')) |
467 | 468 | tellRaw('Potential profanity detected and logged', '[Swore!]') |
@@ -545,8 +546,10 @@ def updateHelp(): |
545 | 546 | f.write(getFileFromServer('https://raw.githubusercontent.com/Tiger-Tom/RunServerDotPy-extras/main/Help/Version')) |
546 | 547 | with open(cacheDir+'help/ChatCommandsHelp.json') as f: |
547 | 548 | chatCommandsHelp,chatCommandsHelpAdmin,chatCommandsHelpRoot = json.load(f) #Load ChatCommands help from cached JSON file |
| 549 | +updateHelp() |
| 550 | + |
548 | 551 | # Remove unusable help strings |
549 | | - if os.name == 'nt': del chatCommandsHelpAdmin['update | upgrade {dist,clean,pip}'] #The necessary commands to update/upgrade are not on Windows, so delete the help string |
| 552 | +if os.name == 'nt': del chatCommandsHelpAdmin['update | upgrade {dist,clean}'] #The necessary commands to update/upgrade are not on Windows, so delete the help string |
550 | 553 |
|
551 | 554 | # Configuration variables |
552 | 555 | sysInfoShown = { |
@@ -602,11 +605,11 @@ def cc_help(ccHelpDict, args, ccPref=chatComPrefix, user='', toConsole=False): # |
602 | 605 | for i in ccHelpDict.keys(): |
603 | 606 | if showAll: |
604 | 607 | if toConsole: print (' • '+i) |
605 | | - else: writeCommand('tellraw '+user+(' [" • ",{"text":"{%COMMAND_FULL}","clickEvent":{"action":"suggest_command","value":"{%COMMAND_SUGGEST}"},"hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_SUGGEST}","bold":true}]}}]').replace('{%COMMAND_FULL}', i).replace('{%COMMAND_SUGGEST}', ccPref+i.split(' ')[0])) |
| 608 | + else: writeCommand('tellraw '+user+(' [" • ",{"text":"{%COMMAND_FULL}","clickEvent":{"action":"suggest_command","value":"{%COMMAND_SUGGEST}"},"hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_SUGGEST}","bold":true}]}}]').replace('{%COMMAND_FULL}', safeTellRaw(i)).replace('{%COMMAND_SUGGEST}', safeTellRaw(ccPref+i.split(' ')[0]))) |
606 | 609 | else: |
607 | 610 | if command in i: |
608 | 611 | if toConsole: print (' • '+i+': '+ccHelpDict[i]) |
609 | | - else: writeCommand('tellraw '+user+(' [" • ",{"text":"{%COMMAND_FULL}","clickEvent":{"action":"suggest_command","value":"{%COMMAND_SUGGEST}"},"hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_SUGGEST}","bold":true}]}},{"text":": {%COMMAND_DESC}","hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_DESC}","bold":true}]}}]').replace('{%COMMAND_FULL}', i).replace('{%COMMAND_SUGGEST}', ccPref+i.split(' ')[0]).replace('{%COMMAND_DESC}', ccHelpDict[i])) |
| 612 | + else: writeCommand('tellraw '+user+(' [" • ",{"text":"{%COMMAND_FULL}","clickEvent":{"action":"suggest_command","value":"{%COMMAND_SUGGEST}"},"hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_SUGGEST}","bold":true}]}},{"text":": {%COMMAND_DESC}","hoverEvent":{"action":"show_text","contents":[{"text":"{%COMMAND_DESC}","bold":true}]}}]').replace('{%COMMAND_FULL}', safeTellRaw(i)).replace('{%COMMAND_SUGGEST}', safeTellRaw(ccPref+i.split(' ')[0])).replace('{%COMMAND_DESC}', safeTellRaw(ccHelpDict[i]))) |
610 | 613 | def cc_parseSpeedTest(res): |
611 | 614 | res = json.loads(res) |
612 | 615 | down = makeValues(res['download'], 1024, sizeVals) |
@@ -652,10 +655,74 @@ def cc_parseTagFlag(flag, user): |
652 | 655 | else: |
653 | 656 | print ('% ERROR: UNKNOWN FLAG "'+str(flag)+'"') |
654 | 657 |
|
| 658 | +# Load ChatCommand mods |
| 659 | +modsRegular = {} |
| 660 | +modsAdmin = {} |
| 661 | +modsRoot = {} |
| 662 | +modded = False |
| 663 | +def loadMods(): |
| 664 | + if not os.path.exists(modDir): #Check if the mod directory exists and create it if it doesn't |
| 665 | + print ('Mods dir doesn\'t exist, creating one now...') |
| 666 | + os.mkdir(modDir) |
| 667 | + modFiles = [f for f in os.listdir(modDir) if os.path.isfile(modDir+'/'+f)] #Find all file in the mod directory |
| 668 | + if not len(modFiles): #If no files/mods were found |
| 669 | + print ('No mods found') |
| 670 | + return False |
| 671 | + mods = [] |
| 672 | + problems = [] |
| 673 | + print ('Loading '+str(len(modFiles))+' mod file(s)...') |
| 674 | + for i in modFiles: #Load all mods |
| 675 | + try: |
| 676 | + with open(modDir+'/'+i) as f: |
| 677 | + print ('Loading mod file '+i+'...') |
| 678 | + exec(f.read()) #Read & parse mod |
| 679 | + global mod_output_ |
| 680 | + mod = mod_output_ |
| 681 | + del mod_output_ |
| 682 | + print ('Checking mod...') |
| 683 | + if len(mod) != 3: #Check if the mod returns 3 arguments |
| 684 | + raise IndexError('Mod doesn\'t return the correct amount of arguments (required: 3, got: '+str(len(mod))+')') |
| 685 | + if (type(mod[0]) != dict) or (type(mod[1]) != dict) or (type(mod[2]) != int): #Check to make sure that the mod returns the correct type of arguments |
| 686 | + raise TypeError('Mod doesn\t return the proper argument types') |
| 687 | + if (mod[2] < 0) or (mod[2] > 2): #Check if the mod's permission level is within the proper bounds |
| 688 | + raise ValueError('Mod doesn\'t returnn the proper permission level (expected: 0-2, got: '+str(mod[2])+')') |
| 689 | + mods.append(mod) #Everything above didn't run, so the mod should be good |
| 690 | + print ('Finished loading mod file '+i) |
| 691 | + except Exception as e: |
| 692 | + print ('Couldn\'t load mod file '+i+' because:\n'+str(e)) |
| 693 | + problems.append((i, e)) |
| 694 | + print ('Finished loading '+str(len(modFiles))+' mod file(s) ('+str(len(mods))+'/'+str(len(modFiles))+' passed checking)') |
| 695 | + if not len(mods): #If mod files were found, but they were all invalid |
| 696 | + print ('No valid mods found') |
| 697 | + return False |
| 698 | + global chatCommandsHelp,chatCommandsHelpAdmin,chatCommandsHelpRoot,modsRegular,modsAdmin,modsRoot |
| 699 | + print ('Applying '+str(len(mods))+' mod(s)...') |
| 700 | + for indx,mod in enumerate(mods): |
| 701 | + print ('Applying mod '+str(indx+1)+'/'+str(len(mods))+'...') |
| 702 | + if mod[2] == 0: #Mod functions have "regular" permission level |
| 703 | + modsRegular.update(mod[1]) |
| 704 | + chatCommandsHelp.update(mod[0]) |
| 705 | + elif mod[2] == 1: #Mod functions have "admin" permission level (requires sudo) |
| 706 | + modsAdmin.update(mod[1]) |
| 707 | + chatCommandsHelpAdmin.update(mod[0]) |
| 708 | + elif mod[2] == 2: #Mod functions have "root" permission level (requires root) |
| 709 | + modsRoot.update(mod[1]) |
| 710 | + chatCommandsHelpRoot.update(mod[0]) |
| 711 | + print ('Applied mod '+str(indx+1)+'/'+str(len(mods))+'\n- Permission level: '+str(mod[2])+'\n- '+str(len(mod[1]))+' new/modified ChatCommands applied\n- '+str(len(mod[0]))+' new/modified help strings applied') |
| 712 | + print ('Successfully applied '+str(len(mods))+' mod(s)') |
| 713 | + if len(problems): #Show all problematic mods |
| 714 | + print ('\n'+str(len(problems))+' mod(s) failed to load:') |
| 715 | + for i,j in problems: |
| 716 | + print ('Failed to load mod file '+str(i)+' because '+str(j)) |
| 717 | + print () |
| 718 | + return True |
| 719 | +loadMods() |
| 720 | + |
655 | 721 | # Basic functions (any user can run) |
656 | 722 | def runChatCommand(cmd, args, user): |
657 | 723 | tellRaw('Running ChatCommand '+cmd, '$ '+user) |
658 | | - if cmd == 'help': cc_help(chatCommandsHelp, args, user=user) #Displays a list of commands, or details for a specific command if it is specified in the arguments |
| 724 | + if len(modsRegular) and (cmd in modsRegular): modsRegular[cmd](args, user) #Check if there are any mod commands loaded, and check the command against any mod commands if they are loaded |
| 725 | + elif cmd == 'help': cc_help(chatCommandsHelp, args, user=user) #Displays a list of commands, or details for a specific command if it is specified in the arguments |
659 | 726 | elif (cmd == 'emoticons') and (user != ccRootUsr): threading.Thread(target=cc_tellrawEmoticons, args=(user,args), daemon=True).start() #Shows a list of copyable emoticons, which are configurable by the server owner |
660 | 727 | elif (cmd == 'nuke') and (user != ccRootUsr): cc_crashPlayer(user, 1) #Secret command |
661 | 728 | elif cmd == 'size': #Displays the size of the server's world folder |
@@ -727,7 +794,8 @@ def runChatCommand(cmd, args, user): |
727 | 794 | # Sudo/admin commands (only admins or server console can run these commands) |
728 | 795 | def runAdminChatCommand(cmd, args, user): |
729 | 796 | tellRaw('Running SuperUser ChatCommand '+cmd, '$'+user, user) |
730 | | - if cmd == 'help': cc_help(chatCommandsHelpAdmin, args, chatComPrefix+'sudo', user) #Display a list of admin commands, or information on a specific one if specified in arguments |
| 797 | + if len(modsAdmin) and (cmd in modsAdmin): modsAdmin[cmd](args, user) #Check if there are any mod commands loaded, and check the command against any mod commands if they are loaded |
| 798 | + elif cmd == 'help': cc_help(chatCommandsHelpAdmin, args, chatComPrefix+'sudo', user) #Display a list of admin commands, or information on a specific one if specified in arguments |
731 | 799 | elif cmd in {'antimalware', 'antivirus', 'scan'}: |
732 | 800 | tellRaw('Operating system: '+os.name, 'AntiMal') |
733 | 801 | if os.name == 'nt': |
@@ -845,7 +913,8 @@ def runAdminChatCommand(cmd, args, user): |
845 | 913 | # Root commands (only server console can run these commands) |
846 | 914 | def runRootChatCommand(cmd, args): |
847 | 915 | print ('$ Running Root ChatCommand '+cmd) |
848 | | - if cmd == 'help': cc_help(chatCommandsHelpRoot, args, chatComPrefix+'root', '', True) |
| 916 | + if len(modsRoot) and (cmd in modsRoot): modsRoot[cmd](args, user) #Check if there are any mod commands loaded, and check the command against any mod commands if they are loaded |
| 917 | + elif cmd == 'help': cc_help(chatCommandsHelpRoot, args, chatComPrefix+'root', '', True) |
849 | 918 | elif cmd == 'clearlogs': |
850 | 919 | global loggedAmountIter, loggedAmountTotal |
851 | 920 | print ('Finishing logs so that they can be safely removed...') |
@@ -954,7 +1023,6 @@ def serverHandler(): #Does everything that is needed to start the server and saf |
954 | 1023 | #Setup functions |
955 | 1024 | keyboard.unhook_all() #Unhook keyboard while processes are running |
956 | 1025 | autoBackup() #Automatically backup everything |
957 | | - updateHelp() #Update the help cache file |
958 | 1026 | swapIcon() #Swap the server icon (if there are any present) |
959 | 1027 | swapMOTD(uptimeStart) #Swap the server MOTD (message of the day) (if there are any present) |
960 | 1028 | makeLogFile() #Setup logging |
|
0 commit comments