rustplus 6.0.10__tar.gz → 6.0.12__tar.gz
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.
- {rustplus-6.0.10/rustplus.egg-info → rustplus-6.0.12}/PKG-INFO +1 -1
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/__init__.py +9 -2
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/__init__.py +1 -0
- rustplus-6.0.12/rustplus/annotations/clan_event.py +21 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/events/__init__.py +1 -0
- rustplus-6.0.12/rustplus/events/chat_event.py +27 -0
- rustplus-6.0.12/rustplus/events/clan_info_event.py +13 -0
- rustplus-6.0.12/rustplus/icons/jungle_ziggurat.png +0 -0
- rustplus-6.0.12/rustplus/icons/radtown.png +0 -0
- rustplus-6.0.12/rustplus/icons/underwater_lab.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/ratelimiter/__init__.py +24 -13
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/websocket/ws.py +39 -25
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/rust_api.py +82 -11
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/__init__.py +1 -0
- rustplus-6.0.12/rustplus/structs/clans/__init__.py +2 -0
- rustplus-6.0.12/rustplus/structs/clans/rust_clan_info.py +247 -0
- rustplus-6.0.12/rustplus/structs/clans/rust_clan_message.py +30 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_chat_message.py +8 -3
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_info.py +19 -1
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_marker.py +9 -0
- {rustplus-6.0.10 → rustplus-6.0.12/rustplus.egg-info}/PKG-INFO +1 -1
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus.egg-info/SOURCES.txt +5 -0
- rustplus-6.0.10/rustplus/events/chat_event.py +0 -13
- rustplus-6.0.10/rustplus/icons/jungle_ziggurat.png +0 -0
- rustplus-6.0.10/rustplus/icons/radtown.png +0 -0
- rustplus-6.0.10/rustplus/icons/underwater_lab.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/LICENSE +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/MANIFEST.in +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/README.md +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/requirements.txt +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/chat_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/command.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/entity_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/protobuf_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/annotations/team_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/commands/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/commands/chat_command.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/commands/chat_command_data.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/commands/command_options.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/events/entity_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/events/protobuf_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/events/team_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/exceptions/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/exceptions/exceptions.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/airfield.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/arctic_base.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/bandit.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/barn.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/cargo.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/chinook.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/chinook_blades.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/crate.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/desert_base.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/dome.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/excavator.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/explosion.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/ferryterminal.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/fishing.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/harbour.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/icon.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/junkyard.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/large_oil_rig.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/launchsite.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/lighthouse.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/military_tunnels.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/mining_outpost.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/mining_quarry_hqm.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/mining_quarry_stone.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/mining_quarry_sulfur.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/missile_silo.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/outpost.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/oxums.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/patrol.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/power_plant.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/satellite.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/sewer.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/small_oil_rig.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/stables.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/supermarket.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/swamp.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/train.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/train_yard.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/vending_machine.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/icons/water_treatment.png +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/identification/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/identification/handler_list.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/identification/registered_listener.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/identification/server_details.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/camera/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/camera/camera_constants.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/camera/camera_manager.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/camera/camera_parser.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/camera/structures.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/fcm/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/fcm/fcm_listener.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/proxy/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/proxy/proxy_value_grabber.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/rustplus_proto/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/rustplus_proto/rustplus.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/remote/websocket/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_contents.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_entity_info.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_error.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_item.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_map.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_team_info.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/rust_time.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/serialization.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/structs/util.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/deprecated.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/emojis.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/fonts/PermanentMarker.ttf +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/fonts/__init__.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/grab_items.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/utils.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus/utils/yielding_event.py +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus.egg-info/dependency_links.txt +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus.egg-info/requires.txt +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/rustplus.egg-info/top_level.txt +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/setup.cfg +0 -0
- {rustplus-6.0.10 → rustplus-6.0.12}/setup.py +0 -0
|
@@ -4,7 +4,14 @@ RustPlus, An API wrapper for interfacing with the Rust+ App API
|
|
|
4
4
|
|
|
5
5
|
from .rust_api import RustSocket
|
|
6
6
|
from .identification import ServerDetails
|
|
7
|
-
from .annotations import
|
|
7
|
+
from .annotations import (
|
|
8
|
+
Command,
|
|
9
|
+
ChatEvent,
|
|
10
|
+
ProtobufEvent,
|
|
11
|
+
TeamEvent,
|
|
12
|
+
EntityEvent,
|
|
13
|
+
ClanEvent,
|
|
14
|
+
)
|
|
8
15
|
from .remote.fcm import FCMListener
|
|
9
16
|
from .remote.camera import MovementControls, CameraMovementOptions
|
|
10
17
|
from .commands import CommandOptions, ChatCommand
|
|
@@ -14,5 +21,5 @@ from .structs import RustError, RustMarker, Vector
|
|
|
14
21
|
|
|
15
22
|
__name__ = "rustplus"
|
|
16
23
|
__author__ = "olijeffers0n"
|
|
17
|
-
__version__ = "6.0.
|
|
24
|
+
__version__ = "6.0.12"
|
|
18
25
|
__support__ = "Discord: https://discord.gg/nQqJe8qvP8"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from .. import ServerDetails
|
|
4
|
+
from ..identification import RegisteredListener
|
|
5
|
+
from ..events import ClanInfoEventPayload as ClanInfoEventManager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def ClanEvent(server_details: ServerDetails) -> Callable:
|
|
9
|
+
|
|
10
|
+
def wrapper(func) -> RegisteredListener:
|
|
11
|
+
|
|
12
|
+
if isinstance(func, RegisteredListener):
|
|
13
|
+
func = func.get_coro()
|
|
14
|
+
|
|
15
|
+
listener = RegisteredListener(func.__name__, func)
|
|
16
|
+
|
|
17
|
+
ClanInfoEventManager.HANDLER_LIST.register(listener, server_details)
|
|
18
|
+
|
|
19
|
+
return listener
|
|
20
|
+
|
|
21
|
+
return wrapper
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from rustplus.identification.handler_list import HandlerList
|
|
2
|
+
from ..structs import RustChatMessage
|
|
3
|
+
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ChatEventPayload:
|
|
8
|
+
HANDLER_LIST = HandlerList()
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self, message: RustChatMessage, is_clan: bool, clan_id: Union[int, None]
|
|
12
|
+
) -> None:
|
|
13
|
+
self._message = message
|
|
14
|
+
self._is_clan = is_clan
|
|
15
|
+
self._clan_id = clan_id
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def message(self) -> RustChatMessage:
|
|
19
|
+
return self._message
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def is_clan(self) -> bool:
|
|
23
|
+
return self._is_clan
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def clan_id(self) -> Union[int, None]:
|
|
27
|
+
return self._clan_id
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from rustplus.identification.handler_list import HandlerList
|
|
2
|
+
from ..structs import RustClanInfo
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ClanInfoEventPayload:
|
|
6
|
+
HANDLER_LIST = HandlerList()
|
|
7
|
+
|
|
8
|
+
def __init__(self, clan_info: RustClanInfo) -> None:
|
|
9
|
+
self._clan_info = clan_info
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def clan_info(self) -> RustClanInfo:
|
|
13
|
+
return self._clan_info
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import math
|
|
2
2
|
import time
|
|
3
|
-
import
|
|
3
|
+
import threading
|
|
4
4
|
from typing import Dict
|
|
5
5
|
|
|
6
6
|
from ...exceptions.exceptions import RateLimitError
|
|
@@ -34,6 +34,8 @@ class TokenBucket:
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class RateLimiter:
|
|
37
|
+
SOCKET_LIMIT = 25
|
|
38
|
+
SOCKET_REFRESH_AMOUNT = 3
|
|
37
39
|
SERVER_LIMIT = 50
|
|
38
40
|
SERVER_REFRESH_AMOUNT = 15
|
|
39
41
|
|
|
@@ -47,7 +49,7 @@ class RateLimiter:
|
|
|
47
49
|
def __init__(self) -> None:
|
|
48
50
|
self.socket_buckets: Dict[ServerDetails, TokenBucket] = {}
|
|
49
51
|
self.server_buckets: Dict[str, TokenBucket] = {}
|
|
50
|
-
self.lock =
|
|
52
|
+
self.lock = threading.Lock()
|
|
51
53
|
|
|
52
54
|
def add_socket(
|
|
53
55
|
self,
|
|
@@ -57,19 +59,21 @@ class RateLimiter:
|
|
|
57
59
|
refresh_rate: float,
|
|
58
60
|
refresh_amount: float,
|
|
59
61
|
) -> None:
|
|
60
|
-
self.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
with self.lock:
|
|
63
|
+
if server_details not in self.socket_buckets:
|
|
64
|
+
self.socket_buckets[server_details] = TokenBucket(
|
|
65
|
+
current, maximum, refresh_rate, refresh_amount
|
|
66
|
+
)
|
|
67
|
+
if server_details.get_server_string() not in self.server_buckets:
|
|
68
|
+
self.server_buckets[server_details.get_server_string()] = TokenBucket(
|
|
69
|
+
self.SERVER_LIMIT, self.SERVER_LIMIT, 1, self.SERVER_REFRESH_AMOUNT
|
|
70
|
+
)
|
|
67
71
|
|
|
68
72
|
async def can_consume(self, server_details: ServerDetails, amount: int = 1) -> bool:
|
|
69
73
|
"""
|
|
70
74
|
Returns whether the user can consume the amount of tokens provided
|
|
71
75
|
"""
|
|
72
|
-
|
|
76
|
+
with self.lock:
|
|
73
77
|
for bucket in [
|
|
74
78
|
self.socket_buckets.get(server_details),
|
|
75
79
|
self.server_buckets.get(server_details.get_server_string()),
|
|
@@ -83,7 +87,7 @@ class RateLimiter:
|
|
|
83
87
|
"""
|
|
84
88
|
Consumes an amount of tokens from the bucket. You should first check to see whether it is possible with can_consume
|
|
85
89
|
"""
|
|
86
|
-
|
|
90
|
+
with self.lock:
|
|
87
91
|
for bucket in [
|
|
88
92
|
self.socket_buckets.get(server_details),
|
|
89
93
|
self.server_buckets.get(server_details.get_server_string()),
|
|
@@ -103,12 +107,14 @@ class RateLimiter:
|
|
|
103
107
|
"""
|
|
104
108
|
Returns how long until the amount of tokens needed will be available
|
|
105
109
|
"""
|
|
106
|
-
|
|
110
|
+
|
|
111
|
+
with self.lock:
|
|
107
112
|
delay = 0
|
|
108
113
|
for bucket in [
|
|
109
114
|
self.socket_buckets.get(server_details),
|
|
110
115
|
self.server_buckets.get(server_details.get_server_string()),
|
|
111
116
|
]:
|
|
117
|
+
bucket.refresh()
|
|
112
118
|
val = (
|
|
113
119
|
math.ceil(
|
|
114
120
|
(
|
|
@@ -127,5 +133,10 @@ class RateLimiter:
|
|
|
127
133
|
"""
|
|
128
134
|
Removes the limiter
|
|
129
135
|
"""
|
|
130
|
-
|
|
136
|
+
with self.lock:
|
|
131
137
|
del self.socket_buckets[server_details]
|
|
138
|
+
server_str = server_details.get_server_string()
|
|
139
|
+
if not any(
|
|
140
|
+
d.get_server_string() == server_str for d in self.socket_buckets
|
|
141
|
+
):
|
|
142
|
+
del self.server_buckets[server_str]
|
|
@@ -19,9 +19,10 @@ from ...events import (
|
|
|
19
19
|
TeamEventPayload,
|
|
20
20
|
ChatEventPayload,
|
|
21
21
|
)
|
|
22
|
+
from ...events.clan_info_event import ClanInfoEventPayload
|
|
22
23
|
from ...exceptions import RequestError
|
|
23
24
|
from ...identification import ServerDetails, RegisteredListener
|
|
24
|
-
from ...structs import RustChatMessage, RustTeamInfo
|
|
25
|
+
from ...structs import RustChatMessage, RustTeamInfo, RustClanInfo
|
|
25
26
|
from ...utils import YieldingEvent, convert_time
|
|
26
27
|
from ...utils.utils import error_present
|
|
27
28
|
|
|
@@ -274,14 +275,40 @@ class RustWebsocket:
|
|
|
274
275
|
for handler in handlers:
|
|
275
276
|
await handler.get_coro()(team_event)
|
|
276
277
|
|
|
277
|
-
elif self.
|
|
278
|
+
elif self.is_clan_broadcast(app_message):
|
|
279
|
+
# Clan Event
|
|
280
|
+
if self.debug:
|
|
281
|
+
self.logger.info(f"Running Clan Event: {app_message}")
|
|
282
|
+
|
|
283
|
+
# This means that the clan of the current player has changed
|
|
284
|
+
handlers = ClanInfoEventPayload.HANDLER_LIST.get_handlers(
|
|
285
|
+
self.server_details
|
|
286
|
+
)
|
|
287
|
+
clan_event = ClanInfoEventPayload(
|
|
288
|
+
RustClanInfo(app_message.broadcast.clan_changed.clan_info)
|
|
289
|
+
)
|
|
290
|
+
for handler in handlers:
|
|
291
|
+
await handler.get_coro()(clan_event)
|
|
292
|
+
|
|
293
|
+
elif self.is_message(app_message) or self.is_clan_message(app_message):
|
|
278
294
|
# Chat message event
|
|
295
|
+
|
|
296
|
+
is_clan = self.is_clan_message(app_message)
|
|
297
|
+
|
|
279
298
|
if self.debug:
|
|
280
|
-
self.logger.info(
|
|
299
|
+
self.logger.info(
|
|
300
|
+
f"Running Chat Event: {app_message}, is_clan={is_clan}"
|
|
301
|
+
)
|
|
281
302
|
|
|
282
303
|
handlers = ChatEventPayload.HANDLER_LIST.get_handlers(self.server_details)
|
|
283
304
|
chat_event = ChatEventPayload(
|
|
284
|
-
RustChatMessage(
|
|
305
|
+
RustChatMessage(
|
|
306
|
+
app_message.broadcast.clan_message.message
|
|
307
|
+
if is_clan
|
|
308
|
+
else app_message.broadcast.team_message.message
|
|
309
|
+
),
|
|
310
|
+
is_clan,
|
|
311
|
+
app_message.broadcast.clan_message.clan_id if is_clan else None,
|
|
285
312
|
)
|
|
286
313
|
for handler in handlers:
|
|
287
314
|
await handler.get_coro()(chat_event)
|
|
@@ -321,6 +348,12 @@ class RustWebsocket:
|
|
|
321
348
|
app_message.broadcast.team_message.message
|
|
322
349
|
)
|
|
323
350
|
|
|
351
|
+
@staticmethod
|
|
352
|
+
def is_clan_message(app_message: AppMessage) -> bool:
|
|
353
|
+
return betterproto.serialized_on_wire(
|
|
354
|
+
app_message.broadcast.clan_message.message
|
|
355
|
+
)
|
|
356
|
+
|
|
324
357
|
@staticmethod
|
|
325
358
|
def is_camera_broadcast(app_message: AppMessage) -> bool:
|
|
326
359
|
return betterproto.serialized_on_wire(app_message.broadcast.camera_rays)
|
|
@@ -334,27 +367,8 @@ class RustWebsocket:
|
|
|
334
367
|
return betterproto.serialized_on_wire(app_message.broadcast.team_changed)
|
|
335
368
|
|
|
336
369
|
@staticmethod
|
|
337
|
-
def
|
|
338
|
-
|
|
339
|
-
Gets the cost of an AppRequest
|
|
340
|
-
"""
|
|
341
|
-
costs = [
|
|
342
|
-
(app_request.get_time, 1),
|
|
343
|
-
(app_request.send_team_message, 2),
|
|
344
|
-
(app_request.get_info, 1),
|
|
345
|
-
(app_request.get_team_chat, 1),
|
|
346
|
-
(app_request.get_team_info, 1),
|
|
347
|
-
(app_request.get_map_markers, 1),
|
|
348
|
-
(app_request.get_map, 5),
|
|
349
|
-
(app_request.set_entity_value, 1),
|
|
350
|
-
(app_request.get_entity_info, 1),
|
|
351
|
-
(app_request.promote_to_leader, 1),
|
|
352
|
-
]
|
|
353
|
-
for request, cost in costs:
|
|
354
|
-
if betterproto.serialized_on_wire(request):
|
|
355
|
-
return cost
|
|
356
|
-
|
|
357
|
-
raise ValueError()
|
|
370
|
+
def is_clan_broadcast(app_message: AppMessage) -> bool:
|
|
371
|
+
return betterproto.serialized_on_wire(app_message.broadcast.clan_changed)
|
|
358
372
|
|
|
359
373
|
@staticmethod
|
|
360
374
|
async def run_coroutine_non_blocking(coroutine: Coroutine) -> Task:
|
|
@@ -31,6 +31,8 @@ from .structs import (
|
|
|
31
31
|
RustEntityInfo,
|
|
32
32
|
RustContents,
|
|
33
33
|
RustItem,
|
|
34
|
+
RustClanInfo,
|
|
35
|
+
RustClanMessage,
|
|
34
36
|
)
|
|
35
37
|
from .structs.rust_error import RustError
|
|
36
38
|
from .utils import (
|
|
@@ -61,13 +63,16 @@ class RustSocket:
|
|
|
61
63
|
self.command_options = command_options
|
|
62
64
|
self.logger = logging.getLogger("rustplus.py")
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
if not self.logger.handlers:
|
|
67
|
+
console_handler = logging.StreamHandler()
|
|
68
|
+
console_handler.setLevel(logging.DEBUG)
|
|
69
|
+
console_handler.setFormatter(
|
|
70
|
+
logging.Formatter(
|
|
71
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
self.logger.addHandler(console_handler)
|
|
75
|
+
self.logger.setLevel(logging.DEBUG)
|
|
71
76
|
|
|
72
77
|
self.ws = RustWebsocket(
|
|
73
78
|
self.server_details,
|
|
@@ -85,10 +90,10 @@ class RustSocket:
|
|
|
85
90
|
|
|
86
91
|
self.ratelimiter.add_socket(
|
|
87
92
|
self.server_details,
|
|
88
|
-
RateLimiter.
|
|
89
|
-
RateLimiter.
|
|
93
|
+
RateLimiter.SOCKET_LIMIT,
|
|
94
|
+
RateLimiter.SOCKET_LIMIT,
|
|
90
95
|
1,
|
|
91
|
-
RateLimiter.
|
|
96
|
+
RateLimiter.SOCKET_REFRESH_AMOUNT,
|
|
92
97
|
)
|
|
93
98
|
|
|
94
99
|
async def _handle_ratelimit(self, tokens) -> None:
|
|
@@ -337,7 +342,7 @@ class RustSocket:
|
|
|
337
342
|
|
|
338
343
|
for marker in map_markers:
|
|
339
344
|
if add_events:
|
|
340
|
-
if marker.type in
|
|
345
|
+
if marker.type in RustMarker.Events:
|
|
341
346
|
icon = convert_marker(int(marker.type), marker.rotation)
|
|
342
347
|
if marker.type == 6:
|
|
343
348
|
x, y = marker.x, marker.y
|
|
@@ -563,3 +568,69 @@ class RustSocket:
|
|
|
563
568
|
return RustError("get_camera_manager", response.response.error.error)
|
|
564
569
|
|
|
565
570
|
return CameraManager(self, cam_id, response.response.camera_subscribe_info)
|
|
571
|
+
|
|
572
|
+
async def get_clan_info(self) -> Union[RustClanInfo, RustError]:
|
|
573
|
+
"""
|
|
574
|
+
Gets the clan information for the player's current clan.
|
|
575
|
+
|
|
576
|
+
:return RustClanInfo: The clan information
|
|
577
|
+
"""
|
|
578
|
+
packet = await self._generate_request(tokens=1)
|
|
579
|
+
packet.get_clan_info = AppEmpty()
|
|
580
|
+
response = await self.ws.send_and_get(packet)
|
|
581
|
+
|
|
582
|
+
if response is None:
|
|
583
|
+
return RustError("get_clan_info", "No response received")
|
|
584
|
+
|
|
585
|
+
if error_present(response):
|
|
586
|
+
return RustError("get_clan_info", response.response.error.error)
|
|
587
|
+
|
|
588
|
+
return RustClanInfo(response.response.clan_info.clan_info)
|
|
589
|
+
|
|
590
|
+
async def get_clan_chat(self) -> Union[List[RustClanMessage], RustError]:
|
|
591
|
+
"""
|
|
592
|
+
Gets the clan chat for the player's current clan.
|
|
593
|
+
|
|
594
|
+
:return List[RustClanMessage]: The clan chat
|
|
595
|
+
"""
|
|
596
|
+
packet = await self._generate_request(tokens=1)
|
|
597
|
+
packet.get_clan_chat = AppEmpty()
|
|
598
|
+
response = await self.ws.send_and_get(packet)
|
|
599
|
+
|
|
600
|
+
if response is None:
|
|
601
|
+
return RustError("get_clan_chat", "No response received")
|
|
602
|
+
|
|
603
|
+
if error_present(response):
|
|
604
|
+
return RustError("get_clan_chat", response.response.error.error)
|
|
605
|
+
|
|
606
|
+
return [
|
|
607
|
+
RustClanMessage(message) for message in response.response.clan_chat.messages
|
|
608
|
+
]
|
|
609
|
+
|
|
610
|
+
async def send_clan_message(self, message: str) -> None:
|
|
611
|
+
"""
|
|
612
|
+
Sends a message to the in-game clan chat
|
|
613
|
+
|
|
614
|
+
:param message: The string message to send
|
|
615
|
+
"""
|
|
616
|
+
|
|
617
|
+
packet = await self._generate_request(tokens=2)
|
|
618
|
+
send_message = AppSendMessage()
|
|
619
|
+
send_message.message = message
|
|
620
|
+
packet.send_clan_message = send_message
|
|
621
|
+
|
|
622
|
+
await self.ws.send_message(packet, True)
|
|
623
|
+
|
|
624
|
+
async def set_clan_motd(self, message: str) -> None:
|
|
625
|
+
"""
|
|
626
|
+
Sets the clan's message of the day
|
|
627
|
+
|
|
628
|
+
:param message: The string message to set as the clan's message of the day
|
|
629
|
+
"""
|
|
630
|
+
|
|
631
|
+
packet = await self._generate_request()
|
|
632
|
+
send_message = AppSendMessage()
|
|
633
|
+
send_message.message = message
|
|
634
|
+
packet.set_clan_motd = send_message
|
|
635
|
+
|
|
636
|
+
await self.ws.send_message(packet, True)
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
from ...remote.rustplus_proto import (
|
|
2
|
+
ClanInfo,
|
|
3
|
+
ClanInfoRole,
|
|
4
|
+
ClanInfoMember,
|
|
5
|
+
ClanInfoInvite,
|
|
6
|
+
)
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RustClanRole:
|
|
11
|
+
def __init__(self, role: ClanInfoRole) -> None:
|
|
12
|
+
self._role_id: int = role.role_id
|
|
13
|
+
self._rank: int = role.rank
|
|
14
|
+
self._name: str = role.name
|
|
15
|
+
self._can_set_motd: bool = role.can_set_motd
|
|
16
|
+
self._can_set_logo: bool = role.can_set_logo
|
|
17
|
+
self._can_invite: bool = role.can_invite
|
|
18
|
+
self._can_kick: bool = role.can_kick
|
|
19
|
+
self._can_promote: bool = role.can_promote
|
|
20
|
+
self._can_demote: bool = role.can_demote
|
|
21
|
+
self._can_set_player_notes: bool = role.can_set_player_notes
|
|
22
|
+
self._can_access_logs: bool = role.can_access_logs
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def role_id(self) -> int:
|
|
26
|
+
return self._role_id
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def rank(self) -> int:
|
|
30
|
+
return self._rank
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> str:
|
|
34
|
+
return self._name
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def can_set_motd(self) -> bool:
|
|
38
|
+
return self._can_set_motd
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def can_set_logo(self) -> bool:
|
|
42
|
+
return self._can_set_logo
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def can_invite(self) -> bool:
|
|
46
|
+
return self._can_invite
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def can_kick(self) -> bool:
|
|
50
|
+
return self._can_kick
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def can_promote(self) -> bool:
|
|
54
|
+
return self._can_promote
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def can_demote(self) -> bool:
|
|
58
|
+
return self._can_demote
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def can_set_player_notes(self) -> bool:
|
|
62
|
+
return self._can_set_player_notes
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def can_access_logs(self) -> bool:
|
|
66
|
+
return self._can_access_logs
|
|
67
|
+
|
|
68
|
+
def __str__(self):
|
|
69
|
+
return (
|
|
70
|
+
"RustClanRole[role_id={}, rank={}, name={}, can_set_motd={}, can_set_logo={}, can_invite={}, "
|
|
71
|
+
"can_kick={}, can_promote={}, can_demote={}, can_set_player_notes={}, can_access_logs={}]"
|
|
72
|
+
).format(
|
|
73
|
+
self._role_id,
|
|
74
|
+
self._rank,
|
|
75
|
+
self._name,
|
|
76
|
+
self._can_set_motd,
|
|
77
|
+
self._can_set_logo,
|
|
78
|
+
self._can_invite,
|
|
79
|
+
self._can_kick,
|
|
80
|
+
self._can_promote,
|
|
81
|
+
self._can_demote,
|
|
82
|
+
self._can_set_player_notes,
|
|
83
|
+
self._can_access_logs,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class RustClanMember:
|
|
88
|
+
def __init__(self, member: ClanInfoMember) -> None:
|
|
89
|
+
self._steam_id: int = member.steam_id
|
|
90
|
+
self._role_id: int = member.role_id
|
|
91
|
+
self._joined_time: int = member.joined
|
|
92
|
+
self._last_seen: int = member.last_seen
|
|
93
|
+
self._notes: str = member.notes
|
|
94
|
+
self._online: bool = member.online
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def steam_id(self) -> int:
|
|
98
|
+
return self._steam_id
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def role_id(self) -> int:
|
|
102
|
+
return self._role_id
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def joined_time(self) -> int:
|
|
106
|
+
return self._joined_time
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def last_seen(self) -> int:
|
|
110
|
+
return self._last_seen
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def notes(self) -> str:
|
|
114
|
+
return self._notes
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def online(self) -> bool:
|
|
118
|
+
return self._online
|
|
119
|
+
|
|
120
|
+
def __str__(self):
|
|
121
|
+
return "RustClanMember[steam_id={}, role_id={}, joined_time={}, last_seen={}, notes={}, online={}]".format(
|
|
122
|
+
self._steam_id,
|
|
123
|
+
self._role_id,
|
|
124
|
+
self._joined_time,
|
|
125
|
+
self._last_seen,
|
|
126
|
+
self._notes,
|
|
127
|
+
self._online,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class RustClanInvite:
|
|
132
|
+
def __init__(self, invite: ClanInfoInvite) -> None:
|
|
133
|
+
self._steam_id: int = invite.steam_id
|
|
134
|
+
self._recruiter: int = invite.recruiter
|
|
135
|
+
self._invited_time: int = invite.timestamp
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def steam_id(self) -> int:
|
|
139
|
+
return self._steam_id
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def recruiter(self) -> int:
|
|
143
|
+
return self._recruiter
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def invited_time(self) -> int:
|
|
147
|
+
return self._invited_time
|
|
148
|
+
|
|
149
|
+
def __str__(self):
|
|
150
|
+
return "RustClanInvite[steam_id={}, recruiter={}, invited_time={}]".format(
|
|
151
|
+
self._steam_id, self._recruiter, self._invited_time
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class RustClanInfo:
|
|
156
|
+
def __init__(self, clan_info: ClanInfo) -> None:
|
|
157
|
+
self._clan_id: int = clan_info.clan_id
|
|
158
|
+
self._clan_name: str = clan_info.name
|
|
159
|
+
self._clan_time_created: int = clan_info.created
|
|
160
|
+
self._creator: int = clan_info.creator
|
|
161
|
+
self._motd: str = clan_info.motd
|
|
162
|
+
self._motd_time_set: int = clan_info.motd_timestamp
|
|
163
|
+
self._motd_author: int = clan_info.motd_author
|
|
164
|
+
self._logo: bytes = clan_info.logo
|
|
165
|
+
self._colour: int = clan_info.color
|
|
166
|
+
self._roles: List[RustClanRole] = [
|
|
167
|
+
RustClanRole(role) for role in clan_info.roles
|
|
168
|
+
]
|
|
169
|
+
self._members: List[RustClanMember] = [
|
|
170
|
+
RustClanMember(member) for member in clan_info.members
|
|
171
|
+
]
|
|
172
|
+
self._invites: List[RustClanInvite] = [
|
|
173
|
+
RustClanInvite(invite) for invite in clan_info.invites
|
|
174
|
+
]
|
|
175
|
+
self._max_members: int = clan_info.max_member_count
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def clan_id(self) -> int:
|
|
179
|
+
return self._clan_id
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
def clan_name(self) -> str:
|
|
183
|
+
return self._clan_name
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def clan_time_created(self) -> int:
|
|
187
|
+
return self._clan_time_created
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def creator(self) -> int:
|
|
191
|
+
return self._creator
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def motd(self) -> str:
|
|
195
|
+
return self._motd
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def motd_time_set(self) -> int:
|
|
199
|
+
return self._motd_time_set
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def motd_author(self) -> int:
|
|
203
|
+
return self._motd_author
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def logo(self) -> bytes:
|
|
207
|
+
return self._logo
|
|
208
|
+
|
|
209
|
+
@property
|
|
210
|
+
def colour(self) -> int:
|
|
211
|
+
return self._colour
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def roles(self) -> List[RustClanRole]:
|
|
215
|
+
return self._roles
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def members(self) -> List[RustClanMember]:
|
|
219
|
+
return self._members
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def invites(self) -> List[RustClanInvite]:
|
|
223
|
+
return self._invites
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def max_members(self) -> int:
|
|
227
|
+
return self._max_members
|
|
228
|
+
|
|
229
|
+
def __str__(self):
|
|
230
|
+
return (
|
|
231
|
+
"RustClanInfo[clan_id={}, clan_name={}, clan_time_created={}, creator={}, motd={}, motd_time_set={}, "
|
|
232
|
+
"motd_author={}, logo={}, colour={}, roles={}, members={}, invites={}, max_members={}]"
|
|
233
|
+
).format(
|
|
234
|
+
self._clan_id,
|
|
235
|
+
self._clan_name,
|
|
236
|
+
self._clan_time_created,
|
|
237
|
+
self._creator,
|
|
238
|
+
self._motd,
|
|
239
|
+
self._motd_time_set,
|
|
240
|
+
self._motd_author,
|
|
241
|
+
self._logo,
|
|
242
|
+
self._colour,
|
|
243
|
+
self._roles,
|
|
244
|
+
self._members,
|
|
245
|
+
self._invites,
|
|
246
|
+
self._max_members,
|
|
247
|
+
)
|