levistone 0.7.1__cp310-cp310-win_amd64.whl → 0.10.5__cp310-cp310-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of levistone might be problematic. Click here for more details.

endstone/__init__.py CHANGED
@@ -1,14 +1,28 @@
1
- from endstone._internal.endstone_python import ColorFormat, GameMode, Logger, OfflinePlayer, Player, Server, Skin
1
+ from endstone._internal.endstone_python import (
2
+ ColorFormat,
3
+ EnchantmentRegistry,
4
+ GameMode,
5
+ ItemRegistry,
6
+ Logger,
7
+ NamespacedKey,
8
+ OfflinePlayer,
9
+ Player,
10
+ Server,
11
+ Skin,
12
+ )
2
13
  from endstone._internal.version import __version__
3
14
 
4
- __minecraft_version__ = "1.21.70"
15
+ __minecraft_version__ = "1.21.102"
5
16
 
6
17
  __all__ = [
7
18
  "__version__",
8
19
  "__minecraft_version__",
9
20
  "ColorFormat",
21
+ "EnchantmentRegistry",
10
22
  "GameMode",
23
+ "ItemRegistry",
11
24
  "Logger",
25
+ "NamespacedKey",
12
26
  "OfflinePlayer",
13
27
  "Player",
14
28
  "Server",
@@ -1,4 +1,5 @@
1
1
  import errno
2
+ import fnmatch
2
3
  import hashlib
3
4
  import logging
4
5
  import os
@@ -15,6 +16,7 @@ import click
15
16
  import importlib_resources
16
17
  import requests
17
18
  import sentry_crashpad
19
+ import tomlkit
18
20
  from packaging.version import Version
19
21
  from rich.progress import BarColumn, DownloadColumn, Progress, TextColumn, TimeRemainingColumn
20
22
 
@@ -110,12 +112,23 @@ class Bootstrap:
110
112
 
111
113
  self._logger.info(f"Integrity check passed. Extracting to {dst}...")
112
114
  dst.mkdir(parents=True, exist_ok=True)
115
+ override_patterns = [
116
+ self.executable_filename,
117
+ "behavior_packs/*",
118
+ "definitions/*",
119
+ "resource_packs/*",
120
+ "bedrock_server_how_to.html",
121
+ "profanity_filter.wlist",
122
+ "release-notes.txt",
123
+ ]
113
124
  with zipfile.ZipFile(f) as zip_ref:
114
125
  for file in zip_ref.namelist():
115
- if file in ["allowlist.json", "permissions.json", "server.properties"] and (dst / file).exists():
116
- self._logger.info(f"{file} already exists, skipping.")
117
- should_modify_server_properties = False
118
- continue
126
+ dest_path = dst / file
127
+ if dest_path.exists():
128
+ if not any(fnmatch.fnmatch(file, pattern) for pattern in override_patterns):
129
+ should_modify_server_properties = False
130
+ self._logger.info(f"{dest_path} already exists, skipping.")
131
+ continue
119
132
 
120
133
  zip_ref.extract(file, dst)
121
134
 
@@ -149,6 +162,28 @@ class Bootstrap:
149
162
  ref = importlib_resources.files("endstone") / "config" / "endstone.toml"
150
163
  with importlib_resources.as_file(ref) as path:
151
164
  shutil.copy(path, self.config_path)
165
+ else:
166
+ ref = importlib_resources.files("endstone") / "config" / "endstone.toml"
167
+ with importlib_resources.as_file(ref) as path:
168
+ with open(path, "r", encoding="utf-8") as f:
169
+ default_config = tomlkit.load(f)
170
+
171
+ with open(self.config_path, "r", encoding="utf-8") as f:
172
+ config = tomlkit.load(f)
173
+
174
+ def migrate_config(from_doc: tomlkit.TOMLDocument, to_doc: tomlkit.TOMLDocument) -> None:
175
+ for key, val in from_doc.items():
176
+ if key not in to_doc:
177
+ # if the user hasn’t set it, copy it (with comments!)
178
+ to_doc[key] = val
179
+ else:
180
+ # if both are tables, dive deeper
181
+ if isinstance(val, tomlkit.TOMLDocument) and isinstance(to_doc[key], tomlkit.TOMLDocument):
182
+ migrate_config(val, to_doc[key])
183
+
184
+ migrate_config(default_config, config)
185
+ with open(self.config_path, "w", encoding="utf-8") as f:
186
+ tomlkit.dump(config, f)
152
187
 
153
188
  def _install(self) -> None:
154
189
  """
@@ -2,7 +2,6 @@ import ctypes.util
2
2
  import os
3
3
  import stat
4
4
  import subprocess
5
- import sys
6
5
  from pathlib import Path
7
6
 
8
7
  from endstone._internal.bootstrap.base import Bootstrap
@@ -41,9 +40,6 @@ class LinuxBootstrap(Bootstrap):
41
40
  def _run(self, *args, **kwargs) -> int:
42
41
  process = subprocess.Popen(
43
42
  [str(self.executable_path.absolute())],
44
- stdin=sys.stdin,
45
- stdout=sys.stdout,
46
- stderr=subprocess.STDOUT,
47
43
  text=True,
48
44
  encoding="utf-8",
49
45
  cwd=str(self.server_path.absolute()),
@@ -1,9 +1,128 @@
1
+ import _winapi
1
2
  import ctypes
2
3
  import os
3
4
  import subprocess
5
+ import warnings
6
+ from subprocess import STARTUPINFO, Handle, list2cmdline
4
7
 
8
+ from endstone._internal import _detours
5
9
  from endstone._internal.bootstrap.base import Bootstrap
6
- from endstone._internal.winext import start_process_with_dll
10
+
11
+
12
+ class PopenWithDll(subprocess.Popen):
13
+ def __init__(self, *args, **kwargs):
14
+ self.dll_names = kwargs.pop("dll_names", None)
15
+ super().__init__(*args, **kwargs)
16
+
17
+ def _execute_child(
18
+ self,
19
+ args,
20
+ executable,
21
+ preexec_fn,
22
+ close_fds,
23
+ pass_fds,
24
+ cwd,
25
+ env,
26
+ startupinfo,
27
+ creationflags,
28
+ shell,
29
+ p2cread,
30
+ p2cwrite,
31
+ c2pread,
32
+ c2pwrite,
33
+ errread,
34
+ errwrite,
35
+ unused_restore_signals,
36
+ unused_gid,
37
+ unused_gids,
38
+ unused_uid,
39
+ unused_umask,
40
+ unused_start_new_session,
41
+ unused_process_group,
42
+ ):
43
+ """Execute program (MS Windows version)"""
44
+
45
+ assert not pass_fds, "pass_fds not supported on Windows."
46
+
47
+ if isinstance(args, str):
48
+ pass
49
+ elif isinstance(args, bytes):
50
+ if shell:
51
+ raise TypeError("bytes args is not allowed on Windows")
52
+ args = list2cmdline([args])
53
+ elif isinstance(args, os.PathLike):
54
+ if shell:
55
+ raise TypeError("path-like args is not allowed when shell is true")
56
+ args = list2cmdline([args])
57
+ else:
58
+ args = list2cmdline(args)
59
+
60
+ if executable is not None:
61
+ executable = os.fsdecode(executable)
62
+
63
+ if startupinfo is None:
64
+ startupinfo = STARTUPINFO()
65
+ else:
66
+ startupinfo = startupinfo.copy()
67
+
68
+ use_std_handles = -1 not in (p2cread, c2pwrite, errwrite)
69
+ if use_std_handles:
70
+ startupinfo.dwFlags |= _winapi.STARTF_USESTDHANDLES
71
+ startupinfo.hStdInput = p2cread
72
+ startupinfo.hStdOutput = c2pwrite
73
+ startupinfo.hStdError = errwrite
74
+
75
+ attribute_list = startupinfo.lpAttributeList
76
+ have_handle_list = bool(attribute_list and "handle_list" in attribute_list and attribute_list["handle_list"])
77
+
78
+ # If we were given an handle_list or need to create one
79
+ if have_handle_list or (use_std_handles and close_fds):
80
+ if attribute_list is None:
81
+ attribute_list = startupinfo.lpAttributeList = {}
82
+ handle_list = attribute_list["handle_list"] = list(attribute_list.get("handle_list", []))
83
+
84
+ if use_std_handles:
85
+ handle_list += [int(p2cread), int(c2pwrite), int(errwrite)]
86
+
87
+ handle_list[:] = self._filter_handle_list(handle_list)
88
+
89
+ if handle_list:
90
+ if not close_fds:
91
+ warnings.warn("startupinfo.lpAttributeList['handle_list'] overriding close_fds", RuntimeWarning)
92
+
93
+ # When using the handle_list we always request to inherit
94
+ # handles but the only handles that will be inherited are
95
+ # the ones in the handle_list
96
+ close_fds = False
97
+
98
+ assert not shell
99
+
100
+ if cwd is not None:
101
+ cwd = os.fsdecode(cwd)
102
+
103
+ # Start the process
104
+ try:
105
+ hp, ht, pid, tid = _detours.CreateProcessWithDllEx(
106
+ executable,
107
+ args,
108
+ # no special security
109
+ None,
110
+ None,
111
+ not close_fds,
112
+ creationflags,
113
+ env,
114
+ cwd,
115
+ startupinfo,
116
+ dll_name=self.dll_names,
117
+ )
118
+ finally:
119
+ self._close_pipe_fds(p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite)
120
+
121
+ # Retain the process handle, but close the thread handle
122
+ self._child_created = True
123
+ self._handle = Handle(hp)
124
+ self.pid = pid
125
+ _winapi.CloseHandle(ht)
7
126
 
8
127
 
9
128
  class WindowsBootstrap(Bootstrap):
@@ -35,7 +154,7 @@ class WindowsBootstrap(Bootstrap):
35
154
  env["_NT_SYMBOL_PATH"] = os.pathsep.join(symbol_path_list)
36
155
  return env
37
156
 
38
- def _add_loopback_exemption(self) -> bool:
157
+ def _add_loopback_exemption(self) -> None:
39
158
  sid = "S-1-15-2-1958404141-86561845-1752920682-3514627264-368642714-62675701-733520436"
40
159
  ret = subprocess.run(
41
160
  ["CheckNetIsolation", "LoopbackExempt", "-s", f"-p={sid}"], check=True, capture_output=True
@@ -44,16 +163,25 @@ class WindowsBootstrap(Bootstrap):
44
163
  ret = ctypes.windll.shell32.ShellExecuteW(
45
164
  None, "runas", "CheckNetIsolation", " ".join(["LoopbackExempt", "-a", f"-p={sid}"]), None, 1
46
165
  )
47
- return ret > 32
48
- else:
49
- return True
166
+ if ret <= 32:
167
+ raise RuntimeError(f"CheckNetIsolation LoopbackExempt -a failed with exit code {ret}.")
50
168
 
51
169
  def _run(self, *args, **kwargs) -> int:
52
- self._add_loopback_exemption()
170
+ try:
171
+ self._add_loopback_exemption()
172
+ except Exception as e:
173
+ self._logger.warning(
174
+ f"Unable to add loopback exemption: %s. See bedrock_server_how_to.html for more details. {e}"
175
+ )
53
176
 
54
- return start_process_with_dll(
55
- str(self.executable_path.absolute()),
56
- str(self._endstone_runtime_path.absolute()),
177
+ process = PopenWithDll(
178
+ [str(self.executable_path.absolute())],
179
+ text=True,
180
+ encoding="utf-8",
57
181
  cwd=str(self.server_path.absolute()),
58
182
  env=self._endstone_runtime_env,
183
+ dll_names=str(self._endstone_runtime_path.absolute()),
184
+ *args,
185
+ **kwargs,
59
186
  )
187
+ return process.wait()