|
5 | 5 | VERSION_MANIFEST = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" |
6 | 6 | BUNGEECORD_DOWNLOAD_URL = "https://ci.md-5.net/job/BungeeCord/lastStableBuild/artifact/bootstrap/target/BungeeCord.jar" |
7 | 7 | APP_VERSION = 1#The API Version. |
8 | | -APP_UF_VERSION = "1.51.1" |
| 8 | +APP_UF_VERSION = "1.52" |
9 | 9 | #The semver version |
10 | 10 | UPDATEINSTALLED = False |
11 | 11 | DOCFILE = "https://github.com/Enderbyte-Programs/CraftServerSetup/raw/main/doc/craftserversetup.epdoc" |
|
43 | 43 | import shlex #Data parsing |
44 | 44 | import re #Pattern matching |
45 | 45 | import typing #HArd types |
| 46 | +import argparse #Arguments system |
46 | 47 |
|
47 | 48 | WINDOWS = platform.system() == "Windows" |
48 | 49 |
|
@@ -408,10 +409,35 @@ def assemble_package_file_path(serverdir:str): |
408 | 409 | PORTABLE = True |
409 | 410 | if "developer" in sfd: |
410 | 411 | DEVELOPER = True |
| 412 | +""" |
411 | 413 | if "-p" in sys.argv or "--portable" in sys.argv: |
412 | 414 | PORTABLE = True |
413 | 415 | if "-d" in sys.argv or "--developer" in sys.argv: |
414 | 416 | DEVELOPER = True |
| 417 | +""" |
| 418 | + |
| 419 | +argparser = argparse. ArgumentParser( "CraftServerSetup", description="A TUI Minecraft Server maker and manager. Run without arguments for a standard interactive experience.", epilog="(c) 2023-2025 Enderbyte programs, some rights reserved. For support, please email [email protected]") |
| 420 | +argparser.add_argument('-p','--portable',action="store_true",required=False,help="Run CraftServerSetup self-contained",dest="p",default=False) |
| 421 | +argparser.add_argument('-d','--developer',action="store_true",required=False,help="Enable debug features",dest="d",default=False) |
| 422 | +argparser.add_argument('-m','--manage',help="Open management UI directly to the server id. Must not be used in conjunction with --start",required=False,default=0,dest="manage_id")#Manage a certain server |
| 423 | +argparser.add_argument("-s",'--start',help="Start the server id provided. Must not be used in conjunction with --manage",required=False,default=0,dest="start_id")#start a certain server |
| 424 | +out = argparser.parse_args() |
| 425 | +PORTABLE = out.p |
| 426 | +DEVELOPER = out.d |
| 427 | + |
| 428 | +try: |
| 429 | + int(out.manage_id) |
| 430 | + int(out.start_id) |
| 431 | +except: |
| 432 | + print("ARGUMENT ERROR - Please specify the server id to manage or start.") |
| 433 | + sys.exit(4) |
| 434 | + |
| 435 | +manageid = int(out.manage_id) |
| 436 | +startid = int(out.start_id) |
| 437 | +if manageid != 0 and startid != 0: |
| 438 | + print("ARGUMENT ERROR - You may not command a manage and a start at the same time.") |
| 439 | + sys.exit(4) |
| 440 | + |
415 | 441 | if not WINDOWS: |
416 | 442 | APPDATADIR = os.path.expanduser("~/.local/share/mcserver") |
417 | 443 | if PORTABLE: |
@@ -3513,6 +3539,150 @@ def resource_warning(stdscr) -> bool: |
3513 | 3539 | else: |
3514 | 3540 | return False |
3515 | 3541 |
|
| 3542 | +def start_server(stdscr,_sname,chosenserver,SERVER_DIR): |
| 3543 | + if sys.version_info[1] < 11: |
| 3544 | + cursesplus.messagebox.showerror(stdscr,["Unfortunately, the new startups can only be used with Python 3.11 or newer.",f"You are running {sys.version}.","Your server will be started in legacy mode (pre 1.43)"]) |
| 3545 | + APPDATA["servers"][chosenserver-1]["settings"]["legacy"] = True |
| 3546 | + os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["launchcommands"])) |
| 3547 | + if APPDATA["servers"][chosenserver-1]["settings"]["legacy"]: |
| 3548 | + os.chdir(APPDATA["servers"][chosenserver-1]["dir"]) |
| 3549 | + stdscr.clear() |
| 3550 | + stdscr.addstr(0,0,f"STARTING {str(datetime.datetime.now())[0:-5]}\n\r") |
| 3551 | + stdscr.refresh() |
| 3552 | + if not WINDOWS: |
| 3553 | + curses.curs_set(1) |
| 3554 | + curses.reset_shell_mode() |
| 3555 | + lretr = os.system(APPDATA["servers"][chosenserver-1]["script"]) |
| 3556 | + #child = pexpect.spawn(APPDATA["servers"][chosenserver-1]["script"]) |
| 3557 | + #child.expect("Finished") |
| 3558 | + curses.reset_prog_mode() |
| 3559 | + curses.curs_set(0) |
| 3560 | + else: |
| 3561 | + curses.curs_set(1) |
| 3562 | + curses.reset_shell_mode() |
| 3563 | + #COLOURS_ACTIVE = False |
| 3564 | + lretr = os.system("cmd /c ("+APPDATA["servers"][chosenserver-1]["script"]+")") |
| 3565 | + curses.reset_prog_mode() |
| 3566 | + curses.curs_set(0) |
| 3567 | + #restart_colour() |
| 3568 | + os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["exitcommands"])) |
| 3569 | + if lretr != 0 and lretr != 127 and lretr != 128 and lretr != 130: |
| 3570 | + displog = cursesplus.messagebox.askyesno(stdscr,["Oh No! Your server crashed","Would you like to view the logs?"]) |
| 3571 | + if displog: |
| 3572 | + view_server_logs(stdscr,SERVER_DIR) |
| 3573 | + stdscr.clear() |
| 3574 | + stdscr.refresh() |
| 3575 | + else: |
| 3576 | + if not _sname in SERVER_INITS: |
| 3577 | + truecommand = APPDATA["servers"][chosenserver-1]["script"] |
| 3578 | + if WINDOWS: |
| 3579 | + truecommand = "cmd /c ("+APPDATA["servers"][chosenserver-1]["script"]+")" |
| 3580 | + SERVER_INITS[_sname] = ServerRunWrapper(truecommand) |
| 3581 | + SERVER_INITS[_sname].launch() |
| 3582 | + cursesplus.messagebox.showinfo(stdscr,["The server has been started.","It will be ready for use in a few minutes"]) |
| 3583 | + latestlogfile = SERVER_DIR+"/logs/latest.log" |
| 3584 | + #pos = 0 |
| 3585 | + obuffer = ["Getting logs. Please wait...","The log may take some time to appear.","Don't worry, your server is still running."] |
| 3586 | + ooffset = 0 |
| 3587 | + oxoffset = 0 |
| 3588 | + tick = 0 |
| 3589 | + #lfsize = os.path.getsize(latestlogfile) |
| 3590 | + stdscr.nodelay(1) |
| 3591 | + |
| 3592 | + redraw = True |
| 3593 | + while True: |
| 3594 | + |
| 3595 | + tick += 1 |
| 3596 | + if tick % 30 == 0: |
| 3597 | + tick = 0 |
| 3598 | + #SERVER_INITS[_sname].datastream.seek(0,0) |
| 3599 | + #obuffer = SERVER_INITS[_sname].datastream.readlines() |
| 3600 | + if os.path.isfile(latestlogfile): |
| 3601 | + mtime = datetime.datetime.fromtimestamp(os.path.getmtime(latestlogfile)) |
| 3602 | + if mtime < SERVER_INITS[_sname].runtime: |
| 3603 | + pass |
| 3604 | + else: |
| 3605 | + |
| 3606 | + with open(latestlogfile) as f: |
| 3607 | + obc = f.readlines() |
| 3608 | + if obc != obuffer: |
| 3609 | + obuffer = obc |
| 3610 | + ooffset = len(obuffer)-my+headeroverhead |
| 3611 | + if ooffset < 0: |
| 3612 | + ooffset = 0 |
| 3613 | + redraw = True |
| 3614 | + |
| 3615 | + #Visual part |
| 3616 | + mx,my = os.get_terminal_size() |
| 3617 | + mx -= 1 |
| 3618 | + my -= 1 |
| 3619 | + headeroverhead = 5 |
| 3620 | + if redraw: |
| 3621 | + stdscr.clear() |
| 3622 | + cursesplus.utils.fill_line(stdscr,0,cursesplus.set_colour(cursesplus.BLUE,cursesplus.WHITE)) |
| 3623 | + stdscr.addstr(0,0,f"Live options for {_sname}",cursesplus.set_colour(cursesplus.BLUE,cursesplus.WHITE)) |
| 3624 | + stdscr.addstr(1,0,"Press B to go back to the options") |
| 3625 | + stdscr.addstr(2,0,"Press C to run a command | Press K to kill the server") |
| 3626 | + stdscr.addstr(3,0,"Press S to stop the server") |
| 3627 | + stdscr.addstr(4,0,cursesplus.constants.THIN_HORIZ_LINE*mx) |
| 3628 | + oi = 5 |
| 3629 | + for line in obuffer[ooffset:]: |
| 3630 | + try: |
| 3631 | + stdscr.addstr(oi,0,line[oxoffset:oxoffset+mx-1]) |
| 3632 | + except: |
| 3633 | + break |
| 3634 | + oi += 1 |
| 3635 | + |
| 3636 | + svrstat = SERVER_INITS[_sname] |
| 3637 | + if not svrstat.isprocessrunning(): |
| 3638 | + |
| 3639 | + stdscr.nodelay(0) |
| 3640 | + os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["exitcommands"])) |
| 3641 | + if svrstat.hascrashed(): |
| 3642 | + displog = cursesplus.messagebox.askyesno(stdscr,["Oh No! Your server crashed","Would you like to view the logs?"]) |
| 3643 | + if displog: |
| 3644 | + view_server_logs(stdscr,SERVER_DIR) |
| 3645 | + else: |
| 3646 | + cursesplus.messagebox.showinfo(stdscr,["The server has been stopped safely."]) |
| 3647 | + del SERVER_INITS[_sname] |
| 3648 | + break |
| 3649 | + #stdscr.addstr(0,0,f"Y: {ooffset} X: {oxoffset}") |
| 3650 | + if redraw: |
| 3651 | + stdscr.refresh() |
| 3652 | + redraw = False |
| 3653 | + ch = stdscr.getch() |
| 3654 | + if ch == curses.KEY_UP and ooffset > 0: |
| 3655 | + ooffset -= 1 |
| 3656 | + redraw = True |
| 3657 | + elif ch == curses.KEY_DOWN: |
| 3658 | + ooffset += 1 |
| 3659 | + redraw = True |
| 3660 | + elif ch == curses.KEY_LEFT and oxoffset > 0: |
| 3661 | + oxoffset -= 1 |
| 3662 | + redraw = True |
| 3663 | + elif ch == curses.KEY_RIGHT: |
| 3664 | + oxoffset += 1 |
| 3665 | + redraw = True |
| 3666 | + |
| 3667 | + elif ch == 98: |
| 3668 | + break |
| 3669 | + elif ch == 99: |
| 3670 | + stdscr.nodelay(0) |
| 3671 | + svrstat.send(crssinput(stdscr,"Enter a command to run")) |
| 3672 | + stdscr.nodelay(1) |
| 3673 | + elif ch == 115: |
| 3674 | + svrstat.send("stop") |
| 3675 | + pass |
| 3676 | + elif ch == 107: |
| 3677 | + stdscr.nodelay(0) |
| 3678 | + if cursesplus.messagebox.askyesno(stdscr,["Are you sure you want to kill the server?","This can corrupt data.","Only do this if you believe the server to be frozen"]): |
| 3679 | + svrstat.fullhalt() |
| 3680 | + stdscr.nodelay(1) |
| 3681 | + |
| 3682 | + sleep(1/30) |
| 3683 | + |
| 3684 | + stdscr.nodelay(0) |
| 3685 | + |
3516 | 3686 | def manage_server(stdscr,_sname: str,chosenserver: int): |
3517 | 3687 | global APPDATA |
3518 | 3688 | global COLOURS_ACTIVE |
@@ -3543,148 +3713,7 @@ def manage_server(stdscr,_sname: str,chosenserver: int): |
3543 | 3713 | break |
3544 | 3714 |
|
3545 | 3715 | elif w == 1: |
3546 | | - if sys.version_info[1] < 11: |
3547 | | - cursesplus.messagebox.showerror(stdscr,["Unfortunately, the new startups can only be used with Python 3.11 or newer.",f"You are running {sys.version}.","Your server will be started in legacy mode (pre 1.43)"]) |
3548 | | - APPDATA["servers"][chosenserver-1]["settings"]["legacy"] = True |
3549 | | - os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["launchcommands"])) |
3550 | | - if APPDATA["servers"][chosenserver-1]["settings"]["legacy"]: |
3551 | | - os.chdir(APPDATA["servers"][chosenserver-1]["dir"]) |
3552 | | - stdscr.clear() |
3553 | | - stdscr.addstr(0,0,f"STARTING {str(datetime.datetime.now())[0:-5]}\n\r") |
3554 | | - stdscr.refresh() |
3555 | | - if not WINDOWS: |
3556 | | - curses.curs_set(1) |
3557 | | - curses.reset_shell_mode() |
3558 | | - lretr = os.system(APPDATA["servers"][chosenserver-1]["script"]) |
3559 | | - #child = pexpect.spawn(APPDATA["servers"][chosenserver-1]["script"]) |
3560 | | - #child.expect("Finished") |
3561 | | - curses.reset_prog_mode() |
3562 | | - curses.curs_set(0) |
3563 | | - else: |
3564 | | - curses.curs_set(1) |
3565 | | - curses.reset_shell_mode() |
3566 | | - #COLOURS_ACTIVE = False |
3567 | | - lretr = os.system("cmd /c ("+APPDATA["servers"][chosenserver-1]["script"]+")") |
3568 | | - curses.reset_prog_mode() |
3569 | | - curses.curs_set(0) |
3570 | | - #restart_colour() |
3571 | | - os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["exitcommands"])) |
3572 | | - if lretr != 0 and lretr != 127 and lretr != 128 and lretr != 130: |
3573 | | - displog = cursesplus.messagebox.askyesno(stdscr,["Oh No! Your server crashed","Would you like to view the logs?"]) |
3574 | | - if displog: |
3575 | | - view_server_logs(stdscr,SERVER_DIR) |
3576 | | - stdscr.clear() |
3577 | | - stdscr.refresh() |
3578 | | - else: |
3579 | | - if not _sname in SERVER_INITS: |
3580 | | - truecommand = APPDATA["servers"][chosenserver-1]["script"] |
3581 | | - if WINDOWS: |
3582 | | - truecommand = "cmd /c ("+APPDATA["servers"][chosenserver-1]["script"]+")" |
3583 | | - SERVER_INITS[_sname] = ServerRunWrapper(truecommand) |
3584 | | - SERVER_INITS[_sname].launch() |
3585 | | - cursesplus.messagebox.showinfo(stdscr,["The server has been started.","It will be ready for use in a few minutes"]) |
3586 | | - latestlogfile = SERVER_DIR+"/logs/latest.log" |
3587 | | - #pos = 0 |
3588 | | - obuffer = ["Getting logs. Please wait...","The log may take some time to appear.","Don't worry, your server is still running."] |
3589 | | - ooffset = 0 |
3590 | | - oxoffset = 0 |
3591 | | - tick = 0 |
3592 | | - #lfsize = os.path.getsize(latestlogfile) |
3593 | | - stdscr.nodelay(1) |
3594 | | - |
3595 | | - redraw = True |
3596 | | - while True: |
3597 | | - |
3598 | | - tick += 1 |
3599 | | - if tick % 30 == 0: |
3600 | | - tick = 0 |
3601 | | - #SERVER_INITS[_sname].datastream.seek(0,0) |
3602 | | - #obuffer = SERVER_INITS[_sname].datastream.readlines() |
3603 | | - if os.path.isfile(latestlogfile): |
3604 | | - mtime = datetime.datetime.fromtimestamp(os.path.getmtime(latestlogfile)) |
3605 | | - if mtime < SERVER_INITS[_sname].runtime: |
3606 | | - pass |
3607 | | - else: |
3608 | | - |
3609 | | - with open(latestlogfile) as f: |
3610 | | - obc = f.readlines() |
3611 | | - if obc != obuffer: |
3612 | | - obuffer = obc |
3613 | | - ooffset = len(obuffer)-my+headeroverhead |
3614 | | - if ooffset < 0: |
3615 | | - ooffset = 0 |
3616 | | - redraw = True |
3617 | | - |
3618 | | - #Visual part |
3619 | | - mx,my = os.get_terminal_size() |
3620 | | - mx -= 1 |
3621 | | - my -= 1 |
3622 | | - headeroverhead = 5 |
3623 | | - if redraw: |
3624 | | - stdscr.clear() |
3625 | | - cursesplus.utils.fill_line(stdscr,0,cursesplus.set_colour(cursesplus.BLUE,cursesplus.WHITE)) |
3626 | | - stdscr.addstr(0,0,f"Live options for {_sname}",cursesplus.set_colour(cursesplus.BLUE,cursesplus.WHITE)) |
3627 | | - stdscr.addstr(1,0,"Press B to go back to the options") |
3628 | | - stdscr.addstr(2,0,"Press C to run a command | Press K to kill the server") |
3629 | | - stdscr.addstr(3,0,"Press S to stop the server") |
3630 | | - stdscr.addstr(4,0,cursesplus.constants.THIN_HORIZ_LINE*mx) |
3631 | | - oi = 5 |
3632 | | - for line in obuffer[ooffset:]: |
3633 | | - try: |
3634 | | - stdscr.addstr(oi,0,line[oxoffset:oxoffset+mx-1]) |
3635 | | - except: |
3636 | | - break |
3637 | | - oi += 1 |
3638 | | - |
3639 | | - svrstat = SERVER_INITS[_sname] |
3640 | | - if not svrstat.isprocessrunning(): |
3641 | | - |
3642 | | - stdscr.nodelay(0) |
3643 | | - os.system(";".join(APPDATA["servers"][chosenserver-1]["settings"]["exitcommands"])) |
3644 | | - if svrstat.hascrashed(): |
3645 | | - displog = cursesplus.messagebox.askyesno(stdscr,["Oh No! Your server crashed","Would you like to view the logs?"]) |
3646 | | - if displog: |
3647 | | - view_server_logs(stdscr,SERVER_DIR) |
3648 | | - else: |
3649 | | - cursesplus.messagebox.showinfo(stdscr,["The server has been stopped safely."]) |
3650 | | - del SERVER_INITS[_sname] |
3651 | | - break |
3652 | | - #stdscr.addstr(0,0,f"Y: {ooffset} X: {oxoffset}") |
3653 | | - if redraw: |
3654 | | - stdscr.refresh() |
3655 | | - redraw = False |
3656 | | - ch = stdscr.getch() |
3657 | | - if ch == curses.KEY_UP and ooffset > 0: |
3658 | | - ooffset -= 1 |
3659 | | - redraw = True |
3660 | | - elif ch == curses.KEY_DOWN: |
3661 | | - ooffset += 1 |
3662 | | - redraw = True |
3663 | | - elif ch == curses.KEY_LEFT and oxoffset > 0: |
3664 | | - oxoffset -= 1 |
3665 | | - redraw = True |
3666 | | - elif ch == curses.KEY_RIGHT: |
3667 | | - oxoffset += 1 |
3668 | | - redraw = True |
3669 | | - |
3670 | | - elif ch == 98: |
3671 | | - break |
3672 | | - elif ch == 99: |
3673 | | - stdscr.nodelay(0) |
3674 | | - svrstat.send(crssinput(stdscr,"Enter a command to run")) |
3675 | | - stdscr.nodelay(1) |
3676 | | - elif ch == 115: |
3677 | | - svrstat.send("stop") |
3678 | | - pass |
3679 | | - elif ch == 107: |
3680 | | - stdscr.nodelay(0) |
3681 | | - if cursesplus.messagebox.askyesno(stdscr,["Are you sure you want to kill the server?","This can corrupt data.","Only do this if you believe the server to be frozen"]): |
3682 | | - svrstat.fullhalt() |
3683 | | - stdscr.nodelay(1) |
3684 | | - |
3685 | | - sleep(1/30) |
3686 | | - |
3687 | | - stdscr.nodelay(0) |
| 3716 | + start_server(stdscr) |
3688 | 3717 | elif w == 2: |
3689 | 3718 | if not os.path.isfile("server.properties"): |
3690 | 3719 | cursesplus.displaymsg(stdscr,["ERROR","server.properties could not be found","Try starting your sever to generate one"]) |
@@ -5362,6 +5391,33 @@ def main(stdscr): |
5362 | 5391 | except: |
5363 | 5392 | with open(UUIDFILE,"wb+") as f: |
5364 | 5393 | f.write(gzip.compress(json.dumps({}).encode())) |
| 5394 | + |
| 5395 | + #Breakaway point for -m and -s tasks |
| 5396 | + _scc = False |
| 5397 | + if manageid != 0: |
| 5398 | + inc = 0 |
| 5399 | + for server in APPDATA["servers"]: |
| 5400 | + if server["id"] == manageid: |
| 5401 | + manage_server(stdscr,server["name"],inc) |
| 5402 | + _scc = True |
| 5403 | + break |
| 5404 | + |
| 5405 | + inc += 1 |
| 5406 | + if not _scc: |
| 5407 | + cursesplus.messagebox.showerror(stdscr,["Unable to find requested","direct manage ID."]) |
| 5408 | + |
| 5409 | + if startid != 0: |
| 5410 | + inc = 0 |
| 5411 | + for server in APPDATA["servers"]: |
| 5412 | + if server["id"] == startid: |
| 5413 | + os.chdir(server["dir"]) |
| 5414 | + start_server(stdscr,server["name"],inc,server["dir"]) |
| 5415 | + _scc = True |
| 5416 | + break |
| 5417 | + |
| 5418 | + inc += 1 |
| 5419 | + if not _scc: |
| 5420 | + cursesplus.messagebox.showerror(stdscr,["Unable to find requested","direct start ID."]) |
5365 | 5421 |
|
5366 | 5422 | #send_telemetry() |
5367 | 5423 | if APPDATA["language"] is None: |
|
0 commit comments