__init__.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import datetime
  2. import json
  3. import os
  4. import ssl
  5. import subprocess
  6. import sys
  7. import typing
  8. import urllib.parse
  9. import urllib.request
  10. """
  11. official api documentation:
  12. https://github.com/ToontownRewritten/api-doc/blob/master/login.md
  13. https://github.com/ToontownRewritten/api-doc/blob/master/invasions.md
  14. """
  15. LOGIN_API_URL = "https://www.toontownrewritten.com/api/login?format=json"
  16. if sys.platform == "darwin":
  17. TOONTOWN_LIBRARY_PATH = os.path.join(
  18. os.path.expanduser("~"), "Library", "Application Support", "Toontown Rewritten",
  19. )
  20. TOONTOWN_ENGINE_DEFAULT_PATH = os.path.join(
  21. TOONTOWN_LIBRARY_PATH, "Toontown Rewritten",
  22. )
  23. else:
  24. TOONTOWN_LIBRARY_PATH = None
  25. TOONTOWN_ENGINE_DEFAULT_PATH = None
  26. def start_engine(engine_path, gameserver, playcookie, **kwargs) -> subprocess.Popen:
  27. env = {
  28. "TTR_GAMESERVER": gameserver,
  29. "TTR_PLAYCOOKIE": playcookie,
  30. }
  31. if sys.platform == "darwin":
  32. env["DYLD_LIBRARY_PATH"] = os.path.join(
  33. TOONTOWN_LIBRARY_PATH, "Libraries.bundle",
  34. )
  35. env["DYLD_FRAMEWORK_PATH"] = os.path.join(TOONTOWN_LIBRARY_PATH, "Frameworks",)
  36. elif sys.platform == "linux" and "XAUTHORITY" in os.environ:
  37. """
  38. Fix for TTREngine reporting:
  39. > :display:x11display(error): Could not open display ":0.0".
  40. > :ToonBase: Default graphics pipe is glxGraphicsPipe (OpenGL).
  41. > :ToonBase(warning): Unable to open 'onscreen' window.
  42. > Traceback (most recent call last):
  43. > File "<compiled '__voltorbmain__'>", line 0, in <module>
  44. > [...]
  45. > File "<compiled 'direct.vlt8f63e471.ShowBase'>", line 0, in vltf05fd21b
  46. > Exception: Could not open window.
  47. """
  48. env["XAUTHORITY"] = os.environ["XAUTHORITY"]
  49. return subprocess.Popen(
  50. args=[engine_path], cwd=os.path.dirname(engine_path), env=env, **kwargs,
  51. )
  52. def api_request(url, params=None, validate_ssl_cert=True):
  53. resp = urllib.request.urlopen(
  54. url=url,
  55. data=urllib.parse.urlencode(params).encode("ascii") if params else None,
  56. context=None if validate_ssl_cert else ssl._create_unverified_context(),
  57. )
  58. return json.loads(resp.read().decode("ascii"))
  59. class _LoginSuccessful:
  60. def __init__(self, playcookie, gameserver):
  61. self.playcookie = playcookie
  62. self.gameserver = gameserver
  63. class _LoginDelayed:
  64. def __init__(self, queue_token):
  65. self.queue_token = queue_token
  66. def login(
  67. username=None, password=None, queue_token=None, validate_ssl_cert=True
  68. ) -> typing.Union[_LoginSuccessful, _LoginDelayed]:
  69. if username is not None and queue_token is None:
  70. assert password is not None
  71. req_params = {
  72. "username": username,
  73. "password": password,
  74. }
  75. elif username is None and queue_token is not None:
  76. req_params = {
  77. "queueToken": queue_token,
  78. }
  79. else:
  80. raise Exception("either specify username or queue token")
  81. resp_data = api_request(
  82. url=LOGIN_API_URL, params=req_params, validate_ssl_cert=validate_ssl_cert,
  83. )
  84. if resp_data["success"] == "true":
  85. return _LoginSuccessful(
  86. playcookie=resp_data["cookie"], gameserver=resp_data["gameserver"],
  87. )
  88. if resp_data["success"] == "delayed":
  89. return _LoginDelayed(queue_token=resp_data["queueToken"],)
  90. raise Exception(repr(resp_data))
  91. def launch(
  92. engine_path, username, password, validate_ssl_certs=True, cpu_limit_percent=None
  93. ) -> None:
  94. result = login(
  95. username=username, password=password, validate_ssl_cert=validate_ssl_certs,
  96. )
  97. if isinstance(result, _LoginDelayed):
  98. result = login(
  99. queue_token=result.queue_token, validate_ssl_cert=validate_ssl_certs,
  100. )
  101. if not isinstance(result, _LoginSuccessful):
  102. raise Exception("unexpected response: {!r}".format(result))
  103. process = start_engine(
  104. engine_path=engine_path,
  105. gameserver=result.gameserver,
  106. playcookie=result.playcookie,
  107. )
  108. if cpu_limit_percent is not None:
  109. subprocess.Popen(
  110. args=[
  111. "cpulimit",
  112. "--pid",
  113. str(process.pid),
  114. "--limit",
  115. str(cpu_limit_percent),
  116. # '--verbose',
  117. ]
  118. )
  119. process.wait()