empire-core 0.7.3__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.
Files changed (67) hide show
  1. empire_core/__init__.py +36 -0
  2. empire_core/_archive/actions.py +511 -0
  3. empire_core/_archive/automation/__init__.py +24 -0
  4. empire_core/_archive/automation/alliance_tools.py +266 -0
  5. empire_core/_archive/automation/battle_reports.py +196 -0
  6. empire_core/_archive/automation/building_queue.py +242 -0
  7. empire_core/_archive/automation/defense_manager.py +124 -0
  8. empire_core/_archive/automation/map_scanner.py +370 -0
  9. empire_core/_archive/automation/multi_account.py +296 -0
  10. empire_core/_archive/automation/quest_automation.py +94 -0
  11. empire_core/_archive/automation/resource_manager.py +380 -0
  12. empire_core/_archive/automation/target_finder.py +153 -0
  13. empire_core/_archive/automation/tasks.py +224 -0
  14. empire_core/_archive/automation/unit_production.py +719 -0
  15. empire_core/_archive/cli.py +68 -0
  16. empire_core/_archive/client_async.py +469 -0
  17. empire_core/_archive/commands.py +201 -0
  18. empire_core/_archive/connection_async.py +228 -0
  19. empire_core/_archive/defense.py +156 -0
  20. empire_core/_archive/events/__init__.py +35 -0
  21. empire_core/_archive/events/base.py +153 -0
  22. empire_core/_archive/events/manager.py +85 -0
  23. empire_core/accounts.py +190 -0
  24. empire_core/client/__init__.py +0 -0
  25. empire_core/client/client.py +459 -0
  26. empire_core/config.py +87 -0
  27. empire_core/exceptions.py +42 -0
  28. empire_core/network/__init__.py +0 -0
  29. empire_core/network/connection.py +378 -0
  30. empire_core/protocol/__init__.py +0 -0
  31. empire_core/protocol/models/__init__.py +339 -0
  32. empire_core/protocol/models/alliance.py +186 -0
  33. empire_core/protocol/models/army.py +444 -0
  34. empire_core/protocol/models/attack.py +229 -0
  35. empire_core/protocol/models/auth.py +216 -0
  36. empire_core/protocol/models/base.py +403 -0
  37. empire_core/protocol/models/building.py +455 -0
  38. empire_core/protocol/models/castle.py +317 -0
  39. empire_core/protocol/models/chat.py +150 -0
  40. empire_core/protocol/models/defense.py +300 -0
  41. empire_core/protocol/models/map.py +269 -0
  42. empire_core/protocol/packet.py +104 -0
  43. empire_core/services/__init__.py +31 -0
  44. empire_core/services/alliance.py +222 -0
  45. empire_core/services/base.py +107 -0
  46. empire_core/services/castle.py +221 -0
  47. empire_core/state/__init__.py +0 -0
  48. empire_core/state/manager.py +398 -0
  49. empire_core/state/models.py +215 -0
  50. empire_core/state/quest_models.py +60 -0
  51. empire_core/state/report_models.py +115 -0
  52. empire_core/state/unit_models.py +75 -0
  53. empire_core/state/world_models.py +269 -0
  54. empire_core/storage/__init__.py +1 -0
  55. empire_core/storage/database.py +237 -0
  56. empire_core/utils/__init__.py +0 -0
  57. empire_core/utils/battle_sim.py +172 -0
  58. empire_core/utils/calculations.py +170 -0
  59. empire_core/utils/crypto.py +8 -0
  60. empire_core/utils/decorators.py +69 -0
  61. empire_core/utils/enums.py +111 -0
  62. empire_core/utils/helpers.py +252 -0
  63. empire_core/utils/response_awaiter.py +153 -0
  64. empire_core/utils/troops.py +93 -0
  65. empire_core-0.7.3.dist-info/METADATA +197 -0
  66. empire_core-0.7.3.dist-info/RECORD +67 -0
  67. empire_core-0.7.3.dist-info/WHEEL +4 -0
@@ -0,0 +1,224 @@
1
+ """
2
+ Asyncio Task Loop Helper
3
+ Inspired by discord.ext.tasks.
4
+
5
+ This module provides a simple way to run background tasks at a specific interval.
6
+ It is designed to be used as a decorator.
7
+
8
+ Usage:
9
+ from empire_core.automation import tasks
10
+
11
+ @tasks.loop(seconds=10)
12
+ async def my_background_task():
13
+ print("Doing something...")
14
+
15
+ my_background_task.start()
16
+ """
17
+
18
+ import asyncio
19
+ import datetime
20
+ import inspect
21
+ import logging
22
+ import traceback
23
+ from typing import Any, Awaitable, Callable, Optional
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class Loop:
29
+ """
30
+ A background task loop.
31
+ Created via the @tasks.loop decorator.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ coro: Callable[..., Awaitable[Any]],
37
+ seconds: float,
38
+ minutes: float,
39
+ hours: float,
40
+ count: Optional[int],
41
+ reconnect: bool,
42
+ loop: Optional[asyncio.AbstractEventLoop],
43
+ ):
44
+ self.coro = coro
45
+ self.seconds = seconds
46
+ self.minutes = minutes
47
+ self.hours = hours
48
+ self.count = count
49
+ self.reconnect = reconnect
50
+ self._loop = loop or asyncio.get_event_loop()
51
+
52
+ self._task: Optional[asyncio.Task] = None
53
+ self._injected_args: tuple = ()
54
+ self._injected_kwargs: dict = {}
55
+ self._stop_next_iteration = False
56
+ self._current_loop = 0
57
+ self._next_iteration: Optional[datetime.datetime] = None
58
+ self._last_iteration: Optional[datetime.datetime] = None
59
+ self._before_loop: Optional[Callable[..., Awaitable[Any]]] = None
60
+ self._after_loop: Optional[Callable[..., Awaitable[Any]]] = None
61
+ self._error_handler: Optional[Callable[[Exception], Awaitable[Any]]] = None
62
+
63
+ # Calculate interval in seconds
64
+ self._interval = seconds + (minutes * 60.0) + (hours * 3600.0)
65
+
66
+ if self._interval < 0:
67
+ raise ValueError("Interval cannot be negative")
68
+
69
+ async def _runner(self, *args, **kwargs):
70
+ """The main loop runner."""
71
+ try:
72
+ if self._before_loop:
73
+ await self._before_loop(*args, **kwargs)
74
+ except Exception as e:
75
+ logger.error(f"Exception in before_loop for {self.coro.__name__}: {e}")
76
+ if self._error_handler:
77
+ await self._error_handler(e)
78
+ return
79
+
80
+ self._current_loop = 0
81
+ self._stop_next_iteration = False
82
+
83
+ # Main execution loop
84
+ while True:
85
+ if self._stop_next_iteration:
86
+ break
87
+
88
+ if self.count is not None and self._current_loop >= self.count:
89
+ break
90
+
91
+ self._last_iteration = datetime.datetime.now(datetime.timezone.utc)
92
+ self._next_iteration = self._last_iteration + datetime.timedelta(seconds=self._interval)
93
+
94
+ try:
95
+ await self.coro(*args, **kwargs)
96
+ except asyncio.CancelledError:
97
+ self._stop_next_iteration = True
98
+ raise
99
+ except Exception as e:
100
+ await self._handle_error(e)
101
+ if not self.reconnect:
102
+ self._stop_next_iteration = True
103
+
104
+ self._current_loop += 1
105
+
106
+ if self._stop_next_iteration:
107
+ break
108
+
109
+ # Sleep until next iteration
110
+ now = datetime.datetime.now(datetime.timezone.utc)
111
+ if now < self._next_iteration:
112
+ sleep_seconds = (self._next_iteration - now).total_seconds()
113
+ await asyncio.sleep(sleep_seconds)
114
+
115
+ try:
116
+ if self._after_loop:
117
+ await self._after_loop(*args, **kwargs)
118
+ except Exception as e:
119
+ logger.error(f"Exception in after_loop for {self.coro.__name__}: {e}")
120
+ await self._handle_error(e)
121
+
122
+ async def _handle_error(self, exception: Exception):
123
+ """Internal error handling dispatch."""
124
+ if self._error_handler:
125
+ try:
126
+ await self._error_handler(exception)
127
+ except Exception as e:
128
+ logger.error(f"Error in error handler for {self.coro.__name__}: {e}")
129
+ else:
130
+ logger.error(f"Unhandled exception in task {self.coro.__name__}: {exception}")
131
+ traceback.print_exc()
132
+
133
+ def start(self, *args, **kwargs):
134
+ """
135
+ Starts the background task.
136
+ arguments passed here are passed to the coroutine.
137
+ """
138
+ if self._task is not None and not self._task.done():
139
+ raise RuntimeError("Task is already running")
140
+
141
+ self._injected_args = args
142
+ self._injected_kwargs = kwargs
143
+ self._task = self._loop.create_task(self._runner(*args, **kwargs))
144
+ return self._task
145
+
146
+ def stop(self):
147
+ """Stops the background task cleanly after the current iteration."""
148
+ self._stop_next_iteration = True
149
+
150
+ def cancel(self):
151
+ """Cancels the background task immediately."""
152
+ if self._task:
153
+ self._task.cancel()
154
+ self._stop_next_iteration = True
155
+
156
+ def restart(self, *args, **kwargs):
157
+ """Restarts the task."""
158
+ self.cancel()
159
+ self.start(*args, **kwargs)
160
+
161
+ def before_loop(self, coro):
162
+ """Decorator to register a coroutine to run before the loop starts."""
163
+ if not inspect.iscoroutinefunction(coro):
164
+ raise TypeError("Expected coroutine function")
165
+ self._before_loop = coro
166
+ return coro
167
+
168
+ def after_loop(self, coro):
169
+ """Decorator to register a coroutine to run after the loop finishes."""
170
+ if not inspect.iscoroutinefunction(coro):
171
+ raise TypeError("Expected coroutine function")
172
+ self._after_loop = coro
173
+ return coro
174
+
175
+ def error(self, coro):
176
+ """Decorator to register a coroutine to handle errors in the loop."""
177
+ if not inspect.iscoroutinefunction(coro):
178
+ raise TypeError("Expected coroutine function")
179
+ self._error_handler = coro
180
+ return coro
181
+
182
+ @property
183
+ def is_running(self) -> bool:
184
+ """Check if the task is currently running."""
185
+ return self._task is not None and not self._task.done()
186
+
187
+ @property
188
+ def current_loop(self) -> int:
189
+ """Get the current iteration count."""
190
+ return self._current_loop
191
+
192
+
193
+ def loop(
194
+ seconds: float = 0,
195
+ minutes: float = 0,
196
+ hours: float = 0,
197
+ count: Optional[int] = None,
198
+ reconnect: bool = True,
199
+ loop: Optional[asyncio.AbstractEventLoop] = None,
200
+ ):
201
+ """
202
+ Decorator to create a background task loop.
203
+
204
+ Args:
205
+ seconds: Duration in seconds between iterations.
206
+ minutes: Duration in minutes.
207
+ hours: Duration in hours.
208
+ count: Optional number of loops to run before stopping.
209
+ reconnect: If True, handles errors and continues. If False, stops on error.
210
+ loop: Optional asyncio loop.
211
+ """
212
+
213
+ def decorator(func: Callable[..., Awaitable[Any]]) -> Loop:
214
+ return Loop(
215
+ func,
216
+ seconds=seconds,
217
+ minutes=minutes,
218
+ hours=hours,
219
+ count=count,
220
+ reconnect=reconnect,
221
+ loop=loop,
222
+ )
223
+
224
+ return decorator