crystalwindow 4.7__py3-none-any.whl → 4.9__py3-none-any.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.
- crystalwindow/__init__.py +10 -0
- crystalwindow/chatvpn.py +82 -0
- crystalwindow/clock.py +11 -0
- crystalwindow/gui.py +1 -1
- crystalwindow/messagebus.py +33 -0
- crystalwindow/tilemap.py +93 -3
- crystalwindow/websearch.py +1 -0
- {crystalwindow-4.7.dist-info → crystalwindow-4.9.dist-info}/METADATA +1 -1
- {crystalwindow-4.7.dist-info → crystalwindow-4.9.dist-info}/RECORD +12 -10
- {crystalwindow-4.7.dist-info → crystalwindow-4.9.dist-info}/WHEEL +0 -0
- {crystalwindow-4.7.dist-info → crystalwindow-4.9.dist-info}/licenses/LICENSE +0 -0
- {crystalwindow-4.7.dist-info → crystalwindow-4.9.dist-info}/top_level.txt +0 -0
crystalwindow/__init__.py
CHANGED
|
@@ -52,6 +52,11 @@ from .websearch import SearchResult, WebBrowse
|
|
|
52
52
|
# === 3D Engine ===
|
|
53
53
|
from .crystal3d import CW3DShape, CW3D
|
|
54
54
|
|
|
55
|
+
# === Chatting/VPN Engine =====
|
|
56
|
+
from .chatvpn import ChatVPN, ChatVPNServer
|
|
57
|
+
|
|
58
|
+
# ==== Message Bus ====
|
|
59
|
+
from .messagebus import send_message, view_message, clear_messages
|
|
55
60
|
|
|
56
61
|
__all__ = [
|
|
57
62
|
# --- Core ---
|
|
@@ -93,4 +98,9 @@ __all__ = [
|
|
|
93
98
|
# --- 3D ---
|
|
94
99
|
"CW3DShape", "CW3D",
|
|
95
100
|
|
|
101
|
+
# --- ChatVPN ---
|
|
102
|
+
"ChatVPN", "ChatVPNServer",
|
|
103
|
+
|
|
104
|
+
# --- Message Bus ---
|
|
105
|
+
"send_message", "view_message", "clear_messages",
|
|
96
106
|
]
|
crystalwindow/chatvpn.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import threading
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# ====================================================
|
|
7
|
+
# ChatVPN SERVER (built into this file)
|
|
8
|
+
# ====================================================
|
|
9
|
+
class ChatVPNServer:
|
|
10
|
+
def __init__(self, host="0.0.0.0", port=9001):
|
|
11
|
+
self.host = host
|
|
12
|
+
self.port = port
|
|
13
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
14
|
+
self.sock.bind((self.host, self.port))
|
|
15
|
+
self.clients = set()
|
|
16
|
+
self.running = False
|
|
17
|
+
|
|
18
|
+
def start(self):
|
|
19
|
+
if self.running:
|
|
20
|
+
return
|
|
21
|
+
self.running = True
|
|
22
|
+
print(f"[ChatVPN-Server] running on {self.host}:{self.port}")
|
|
23
|
+
threading.Thread(target=self._loop, daemon=True).start()
|
|
24
|
+
|
|
25
|
+
def _loop(self):
|
|
26
|
+
while self.running:
|
|
27
|
+
data, addr = self.sock.recvfrom(4096)
|
|
28
|
+
|
|
29
|
+
if addr not in self.clients:
|
|
30
|
+
self.clients.add(addr)
|
|
31
|
+
print(f"[ChatVPN-Server] new client: {addr}")
|
|
32
|
+
|
|
33
|
+
for c in self.clients:
|
|
34
|
+
if c != addr:
|
|
35
|
+
self.sock.sendto(data, c)
|
|
36
|
+
|
|
37
|
+
def stop(self):
|
|
38
|
+
self.running = False
|
|
39
|
+
self.sock.close()
|
|
40
|
+
print("[ChatVPN-Server] stopped.")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ====================================================
|
|
44
|
+
# ChatVPN CLIENT
|
|
45
|
+
# ====================================================
|
|
46
|
+
class ChatVPN:
|
|
47
|
+
def __init__(self, server_ip: str, port: int = 9001):
|
|
48
|
+
self.server = (server_ip, port)
|
|
49
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
50
|
+
self.running = False
|
|
51
|
+
self._on_msg = None
|
|
52
|
+
|
|
53
|
+
def start(self):
|
|
54
|
+
if self.running:
|
|
55
|
+
return
|
|
56
|
+
self.running = True
|
|
57
|
+
threading.Thread(target=self._recv_loop, daemon=True).start()
|
|
58
|
+
print(f"[ChatVPN-Client] connected to {self.server}")
|
|
59
|
+
|
|
60
|
+
def send(self, text: str):
|
|
61
|
+
packet = json.dumps({"type": "text", "data": text}).encode()
|
|
62
|
+
self.sock.sendto(packet, self.server)
|
|
63
|
+
|
|
64
|
+
def on_msg(self, func):
|
|
65
|
+
self._on_msg = func
|
|
66
|
+
|
|
67
|
+
def _recv_loop(self):
|
|
68
|
+
while self.running:
|
|
69
|
+
try:
|
|
70
|
+
data, _ = self.sock.recvfrom(4096)
|
|
71
|
+
except OSError:
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
obj = json.loads(data.decode())
|
|
76
|
+
msg = obj.get("data", "")
|
|
77
|
+
except:
|
|
78
|
+
msg = data.decode()
|
|
79
|
+
|
|
80
|
+
if self._on_msg:
|
|
81
|
+
self._on_msg(msg)
|
|
82
|
+
|
crystalwindow/clock.py
CHANGED
|
@@ -45,6 +45,7 @@ class Clock:
|
|
|
45
45
|
|
|
46
46
|
# FPS
|
|
47
47
|
self.target_fps = target_fps
|
|
48
|
+
self.timer = CountdownTimer()
|
|
48
49
|
self.min_frame_time = 1 / target_fps if target_fps else 0
|
|
49
50
|
self.frame_times = deque(maxlen=smooth_fps)
|
|
50
51
|
|
|
@@ -145,3 +146,13 @@ class Clock:
|
|
|
145
146
|
def timestamp(self):
|
|
146
147
|
"""High-precision monotonic timestamp."""
|
|
147
148
|
return time.perf_counter()
|
|
149
|
+
|
|
150
|
+
#TIMER
|
|
151
|
+
def start_timer(self, seconds: float):
|
|
152
|
+
self.timer.start(seconds)
|
|
153
|
+
|
|
154
|
+
def timer_ended(self):
|
|
155
|
+
return self.timer.is_finished()
|
|
156
|
+
|
|
157
|
+
def timer_remaining(self):
|
|
158
|
+
return self.timer.get_remaining()
|
crystalwindow/gui.py
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# crystalwindow/messagebus.py
|
|
2
|
+
|
|
3
|
+
class MessageBus:
|
|
4
|
+
def __init__(self):
|
|
5
|
+
self._queue = []
|
|
6
|
+
|
|
7
|
+
def send(self, name: str, data=None):
|
|
8
|
+
self._queue.append({
|
|
9
|
+
"name": name,
|
|
10
|
+
"data": data
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
def poll(self, name: str):
|
|
14
|
+
for msg in self._queue:
|
|
15
|
+
if msg["name"] == name:
|
|
16
|
+
self._queue.remove(msg)
|
|
17
|
+
return msg["data"]
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
def clear(self):
|
|
21
|
+
self._queue.clear()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_bus = MessageBus()
|
|
25
|
+
|
|
26
|
+
def send_message(name: str, data=None):
|
|
27
|
+
_bus.send(name, data)
|
|
28
|
+
|
|
29
|
+
def view_message(name: str):
|
|
30
|
+
return _bus.poll(name)
|
|
31
|
+
|
|
32
|
+
def clear_messages():
|
|
33
|
+
_bus.clear()
|
crystalwindow/tilemap.py
CHANGED
|
@@ -1,13 +1,103 @@
|
|
|
1
1
|
from .sprites import Sprite
|
|
2
2
|
|
|
3
3
|
class TileMap:
|
|
4
|
-
def __init__(self, tile_size):
|
|
4
|
+
def __init__(self, tile_size=32):
|
|
5
5
|
self.tile_size = tile_size
|
|
6
|
-
self.tiles = []
|
|
6
|
+
self.tiles = [] # list of Sprite
|
|
7
7
|
|
|
8
8
|
def add_tile(self, image, x, y):
|
|
9
|
-
|
|
9
|
+
"""Add a tile snapped to grid."""
|
|
10
|
+
gx = x // self.tile_size * self.tile_size
|
|
11
|
+
gy = y // self.tile_size * self.tile_size
|
|
12
|
+
tile = Sprite((gx, gy), (self.tile_size, self.tile_size), image=image)
|
|
13
|
+
self.tiles.append(tile)
|
|
14
|
+
return tile
|
|
15
|
+
|
|
16
|
+
def remove_tile_at(self, x, y):
|
|
17
|
+
"""Remove a tile that sits on this grid cell."""
|
|
18
|
+
gx = x // self.tile_size * self.tile_size
|
|
19
|
+
gy = y // self.tile_size * self.tile_size
|
|
20
|
+
for t in self.tiles:
|
|
21
|
+
if t.pos[0] == gx and t.pos[1] == gy:
|
|
22
|
+
self.tiles.remove(t)
|
|
23
|
+
return True
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
def get_tile_at(self, x, y):
|
|
27
|
+
"""Return tile located at the grid coords."""
|
|
28
|
+
gx = x // self.tile_size * self.tile_size
|
|
29
|
+
gy = y // self.tile_size * self.tile_size
|
|
30
|
+
for t in self.tiles:
|
|
31
|
+
if t.pos[0] == gx and t.pos[1] == gy:
|
|
32
|
+
return t
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
def to_data(self):
|
|
36
|
+
"""Convert to serializable list for saving."""
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
"x": t.pos[0],
|
|
40
|
+
"y": t.pos[1],
|
|
41
|
+
"image_id": t.image_id if hasattr(t, "image_id") else None
|
|
42
|
+
}
|
|
43
|
+
for t in self.tiles
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
def load_data(self, data, image_loader):
|
|
47
|
+
"""
|
|
48
|
+
Load tiles from list.
|
|
49
|
+
image_loader(id) → returns the image object used by Sprite.
|
|
50
|
+
"""
|
|
51
|
+
self.tiles = []
|
|
52
|
+
for d in data:
|
|
53
|
+
img = image_loader(d["image_id"])
|
|
54
|
+
tile = Sprite((d["x"], d["y"]),
|
|
55
|
+
(self.tile_size, self.tile_size),
|
|
56
|
+
image=img)
|
|
57
|
+
if img is not None:
|
|
58
|
+
tile.image_id = d["image_id"]
|
|
59
|
+
self.tiles.append(tile)
|
|
10
60
|
|
|
11
61
|
def draw(self, win):
|
|
62
|
+
"""Draw all tiles."""
|
|
12
63
|
for t in self.tiles:
|
|
13
64
|
win.draw_sprite(t)
|
|
65
|
+
class Grid:
|
|
66
|
+
def __init__(self, win, cell_size=(16, 16)):
|
|
67
|
+
self.win = win
|
|
68
|
+
self.cell_w, self.cell_h = cell_size
|
|
69
|
+
self.update_size()
|
|
70
|
+
|
|
71
|
+
def update_size(self):
|
|
72
|
+
self.w, self.h = self.win.size
|
|
73
|
+
|
|
74
|
+
self.cols = self.w // self.cell_w
|
|
75
|
+
self.rows = self.h // self.cell_h
|
|
76
|
+
self.cells = [(cx, cy) for cy in range(self.rows) for cx in range(self.cols)]
|
|
77
|
+
|
|
78
|
+
# MAKES GRID WORK LIKE gameg(x, y)
|
|
79
|
+
def __call__(self, x, y):
|
|
80
|
+
"""Return cell index for given pixel pos."""
|
|
81
|
+
return x // self.cell_w, y // self.cell_h
|
|
82
|
+
|
|
83
|
+
def snap(self, x, y):
|
|
84
|
+
gx = x // self.cell_w * self.cell_w
|
|
85
|
+
gy = y // self.cell_h * self.cell_h
|
|
86
|
+
return gx, gy
|
|
87
|
+
|
|
88
|
+
def get_cell(self, x, y):
|
|
89
|
+
return x // self.cell_w, y // self.cell_h
|
|
90
|
+
|
|
91
|
+
def cell_to_px(self, cx, cy):
|
|
92
|
+
return cx * self.cell_w, cy * self.cell_h
|
|
93
|
+
|
|
94
|
+
def draw(self, color=(200, 200, 200)):
|
|
95
|
+
self.update_size()
|
|
96
|
+
|
|
97
|
+
# vertical
|
|
98
|
+
for x in range(0, self.w, self.cell_w):
|
|
99
|
+
self.win.draw_line((x, 0), (x, self.h), color)
|
|
100
|
+
|
|
101
|
+
# horizontal
|
|
102
|
+
for y in range(0, self.h, self.cell_h):
|
|
103
|
+
self.win.draw_line((0, y), (self.w, y), color)
|
crystalwindow/websearch.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.9
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (ME)! Easier apps, smoother UI and all-in-one helpers!, Gui, Buttons, FileHelper, Sprites, Animations, Colors, Math, Gravity, Camera, 3D and more!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
crystalwindow/FileHelper.py,sha256=U20iwND4jX1y91TOK46e8MPH8xyw7GOrZ697nPEnOPk,10706
|
|
2
|
-
crystalwindow/__init__.py,sha256=
|
|
2
|
+
crystalwindow/__init__.py,sha256=3YBPnMJuc-jatE__Ts-cs5s2J1OWeDE7HzgCv95ykdA,2823
|
|
3
3
|
crystalwindow/ai.py,sha256=YIt6dNe1QljSAlNECCVa3DMUSIqQEJRIAAbQpYqFNNo,11525
|
|
4
4
|
crystalwindow/animation.py,sha256=zHjrdBXQeyNaLAuaGPldJueX05OZ5j31YR8NizmR0uQ,427
|
|
5
5
|
crystalwindow/assets.py,sha256=8MxPSk7W5YcBnKDh6KcLdg34uxmACf_m6feSYFCWHqA,11405
|
|
6
6
|
crystalwindow/camera.py,sha256=tbn4X-jxMIszAUg3Iu-89gJN5nij0mjPMEzGotcLbJI,712
|
|
7
|
-
crystalwindow/
|
|
7
|
+
crystalwindow/chatvpn.py,sha256=Ij3wRNrMbPINO-SX9vx8xlrKRLvG7zJgzAN2T0jzSz8,2477
|
|
8
|
+
crystalwindow/clock.py,sha256=LZUm4WoAnJuGA-efRKkLHRE9cxCs3pRhwcZZF14fIKA,5109
|
|
8
9
|
crystalwindow/collision.py,sha256=hpkHTp_KparghVK-itp_rxuYdd2GbQMxICHlUBv0rSw,472
|
|
9
10
|
crystalwindow/color_handler.py,sha256=K3LipCPOjYt1NemeT-hNWf886LL59QgRN8ifHOi7-0M,3255
|
|
10
11
|
crystalwindow/crystal3d.py,sha256=8n42S71NZWgBgYwP8ZWfobXFeWvNrhJY80YGK-PzI8s,5375
|
|
@@ -14,14 +15,15 @@ crystalwindow/draw_text_helper.py,sha256=qv5fFCuTCKWeGDk9Z_ZpOzrTFP8YYwlgQrrorwr
|
|
|
14
15
|
crystalwindow/draw_tool.py,sha256=1YYEqjmgt4HpV3S15sTjCSmcqgHup4fD8gskTkxU0t4,1638
|
|
15
16
|
crystalwindow/fun_helpers.py,sha256=x-OF5dlMlHgvXjtT7Om8RvzKWgizSwnzeaM0_W3-SKQ,870
|
|
16
17
|
crystalwindow/gravity.py,sha256=pZJykZzO-mKVBPsZRP55nnlvUoYQfR29wPgJcI4IbBs,2904
|
|
17
|
-
crystalwindow/gui.py,sha256=
|
|
18
|
+
crystalwindow/gui.py,sha256=_T4diMardg50gk0_OBpFHfJo5Coo-D3aZt3Vl6PJjxQ,5287
|
|
18
19
|
crystalwindow/gui_ext.py,sha256=JctpNPr7gtGdro3csyUo9ft3FFArj3JhkVlgKF0lyME,3407
|
|
19
20
|
crystalwindow/math.py,sha256=slOY3KQZ99VDMUMxsSJabMyRtJcwVzEyxR2RoXspHho,963
|
|
21
|
+
crystalwindow/messagebus.py,sha256=9K2P_TkdQ1rt-oouIkRg_XHwMTwykttBt-9gFYaItyI,696
|
|
20
22
|
crystalwindow/objects.py,sha256=VCEvRrzPv-bWCiVw63rMF67KYluP6FKySgDOvOiN8QU,5413
|
|
21
23
|
crystalwindow/sprites.py,sha256=IADCQetFDQoat3qGpKkH93TdtqqgldfHl4N0HKX1Ajc,7480
|
|
22
|
-
crystalwindow/tilemap.py,sha256=
|
|
24
|
+
crystalwindow/tilemap.py,sha256=endJ8KcbP9EjPvL9qWsOpV4jc_Re1yH080aUyDkwufA,3378
|
|
23
25
|
crystalwindow/ver_warner.py,sha256=qEN3ulc1NixBy15FFx2R3Zu0DhyJTVJwiESGAPwpynM,3373
|
|
24
|
-
crystalwindow/websearch.py,sha256=
|
|
26
|
+
crystalwindow/websearch.py,sha256=IgsoKt27yCBHeq8yFVfSq_8sEj5KP6mqn2yNRTsRw1A,5161
|
|
25
27
|
crystalwindow/window.py,sha256=qfz0e8dhLH0ZfoqjswFu20NJqh3Ln6rhaZ3v626Uewk,31849
|
|
26
28
|
crystalwindow/Icons/default_icon.png,sha256=Loq27Pxb8Wb3Sz-XwtNF1RmlLNxR4TcfOWfK-1lWcII,7724
|
|
27
29
|
crystalwindow/Icons/file_icons.png,sha256=kqjvz3gMaIbepW4XGrLZOjDYu-yhFbVxjvylS-0RO4U,5659
|
|
@@ -36,8 +38,8 @@ crystalwindow/gametests/sandbox.py,sha256=Oo2tU2N0y3BPVa6T5vs_h9N6islhQrjSrr_78X
|
|
|
36
38
|
crystalwindow/gametests/squaremove.py,sha256=ei6DMnvcgpOhmxbGv-Yqmx5EqiZjKbVlZhI7YbT2hY8,643
|
|
37
39
|
crystalwindow/gametests/testtttagain.py,sha256=oIhK9MGgMVly_W2lRwD9Hn9WyPdd8JnX2HGrLTGZdxY,373
|
|
38
40
|
crystalwindow/gametests/windowtesting.py,sha256=_9X6wnV1-_X_PtNS-0zu-k209NtFIwAc4vpxLPp7V2o,97
|
|
39
|
-
crystalwindow-4.
|
|
40
|
-
crystalwindow-4.
|
|
41
|
-
crystalwindow-4.
|
|
42
|
-
crystalwindow-4.
|
|
43
|
-
crystalwindow-4.
|
|
41
|
+
crystalwindow-4.9.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
|
|
42
|
+
crystalwindow-4.9.dist-info/METADATA,sha256=9CY3r5w-s8NAWe5ynIBOWOehMyRDro-zXnhhPw1yL2Q,7523
|
|
43
|
+
crystalwindow-4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
crystalwindow-4.9.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
|
|
45
|
+
crystalwindow-4.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|