awacke1 commited on
Commit
f9e5e02
ยท
verified ยท
1 Parent(s): 6881280

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -71
app.py CHANGED
@@ -9,13 +9,28 @@ from pathlib import Path
9
  import base64
10
  from io import BytesIO
11
  import numpy as np
 
 
 
 
12
 
 
13
  GRID_WIDTH = 16
14
  GRID_HEIGHT = 9
15
  REFRESH_RATE = 5
16
  INTERACTION_RADIUS = 2
17
  POINTS_PER_INTERACTION = 1
18
 
 
 
 
 
 
 
 
 
 
 
19
  @st.cache_resource(show_spinner="Loading game resources...")
20
  def get_game_images():
21
  return {
@@ -24,6 +39,7 @@ def get_game_images():
24
  'other_player': Image.new('RGB', (50, 50), color='red')
25
  }
26
 
 
27
  @st.cache_data
28
  def get_name_components():
29
  return {
@@ -33,7 +49,8 @@ def get_name_components():
33
  'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix']
34
  }
35
 
36
- @st.cache_data(ttl=5)
 
37
  def load_all_players(timestamp):
38
  players = {}
39
  if os.path.exists('players'):
@@ -46,52 +63,75 @@ def load_all_players(timestamp):
46
  players[player_data['name']] = player_data
47
  except json.JSONDecodeError:
48
  continue
49
- return {'players': players, 'last_update': time.time()}
50
 
51
- def clear_caches():
52
- st.cache_resource.clear()
53
- st.cache_data.clear()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- def generate_fantasy_name():
56
- name_parts = get_name_components()
57
- return random.choice(name_parts['prefixes']) + random.choice(name_parts['suffixes'])
 
 
 
 
 
 
 
 
 
58
 
59
- def load_game_state():
60
- if 'player_name' in st.query_params:
61
- st.session_state.player_name = st.query_params.player_name
62
- st.session_state.position = {
63
- 'x': int(st.query_params.get('x', random.randint(0, GRID_WIDTH - 1))),
64
- 'y': int(st.query_params.get('y', random.randint(0, GRID_HEIGHT - 1)))
65
- }
66
- st.session_state.character_stats = {
67
- 'STR': int(st.query_params.get('STR', 10)),
68
- 'DEX': int(st.query_params.get('DEX', 10)),
69
- 'CON': int(st.query_params.get('CON', 10)),
70
- 'INT': int(st.query_params.get('INT', 10)),
71
- 'WIS': int(st.query_params.get('WIS', 10)),
72
- 'CHA': int(st.query_params.get('CHA', 10)),
73
- 'HP': int(st.query_params.get('HP', 20)),
74
- 'MAX_HP': int(st.query_params.get('MAX_HP', 40)),
75
- 'score': int(st.query_params.get('score', 0)),
76
- 'created_at': float(st.query_params.get('created_at', time.time()))
77
- }
78
 
 
79
  def save_game_state():
80
  if st.session_state.player_name and st.session_state.character_stats:
81
  params = {
82
  'player_name': st.session_state.player_name,
83
  'x': str(st.session_state.position['x']),
84
  'y': str(st.session_state.position['y']),
85
- **{k: str(v) for k, v in st.session_state.character_stats.items()}
 
86
  }
87
  st.query_params.from_dict(params)
88
 
 
89
  if 'initialized' not in st.session_state:
90
  st.session_state.initialized = False
91
  st.session_state.game_state = {
92
  'players': {},
93
  'chat_messages': [],
94
- 'last_sync': time.time()
95
  }
96
  st.session_state.player_name = None
97
  st.session_state.character_stats = None
@@ -99,28 +139,30 @@ if 'initialized' not in st.session_state:
99
  'x': random.randint(0, GRID_WIDTH - 1),
100
  'y': random.randint(0, GRID_HEIGHT - 1)
101
  }
102
- st.session_state.last_move = time.time()
103
  st.session_state.nearby_players = []
104
- load_game_state()
105
 
 
106
  def save_player_state():
107
  if st.session_state.player_name:
108
  player_data = {
109
  'name': st.session_state.player_name,
110
  'position': st.session_state.position,
111
  'stats': st.session_state.character_stats,
112
- 'last_update': time.time()
113
  }
114
  os.makedirs('players', exist_ok=True)
115
  with open(f"players/{st.session_state.player_name}.json", 'w') as f:
116
  json.dump(player_data, f)
117
  save_game_state()
118
 
 
119
  def calculate_distance(pos1, pos2):
120
  dx = min(abs(pos1['x'] - pos2['x']), GRID_WIDTH - abs(pos1['x'] - pos2['x']))
121
  dy = min(abs(pos1['y'] - pos2['y']), GRID_HEIGHT - abs(pos1['y'] - pos2['y']))
122
  return dx + dy
123
 
 
124
  def update_position(direction):
125
  if direction == "up":
126
  st.session_state.position['y'] = (st.session_state.position['y'] - 1) % GRID_HEIGHT
@@ -130,11 +172,12 @@ def update_position(direction):
130
  st.session_state.position['x'] = (st.session_state.position['x'] - 1) % GRID_WIDTH
131
  elif direction == "right":
132
  st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH
133
- st.session_state.last_move = time.time()
134
  save_player_state()
135
 
 
136
  def update_nearby_players():
137
- current_time = time.time()
138
  all_players = load_all_players(current_time)['players']
139
  nearby = []
140
  score_gain = 0
@@ -145,7 +188,8 @@ def update_nearby_players():
145
  nearby.append({
146
  'name': player_name,
147
  'distance': distance,
148
- 'score': player_data['stats']['score']
 
149
  })
150
  score_gain += POINTS_PER_INTERACTION
151
  if score_gain > 0:
@@ -153,10 +197,12 @@ def update_nearby_players():
153
  save_player_state()
154
  st.session_state.nearby_players = nearby
155
 
 
156
  def create_game_board():
157
- current_time = time.time()
158
  all_players = load_all_players(current_time)['players']
159
  images = get_game_images()
 
160
  for y in range(GRID_HEIGHT):
161
  cols = st.columns(GRID_WIDTH)
162
  for x in range(GRID_WIDTH):
@@ -165,6 +211,7 @@ def create_game_board():
165
  if (player_data['position']['x'] == x and
166
  player_data['position']['y'] == y):
167
  player_here = player_name
 
168
  if x == st.session_state.position['x'] and y == st.session_state.position['y']:
169
  cols[x].image(images['player'], use_column_width=True)
170
  cols[x].markdown(f"**You** ({st.session_state.character_stats['score']} pts)")
@@ -174,38 +221,7 @@ def create_game_board():
174
  else:
175
  cols[x].image(images['tile'], use_column_width=True)
176
 
177
- def create_autorefresh():
178
- refresh_html = """
179
- <script>
180
- let lastUpdate = Date.now();
181
-
182
- function checkForUpdates() {
183
- const now = Date.now();
184
- if (now - lastUpdate >= 5000) {
185
- lastUpdate = now;
186
- window.parent.document.querySelector('.stApp').classList.add('refreshing');
187
- setTimeout(() => window.location.reload(), 100);
188
- }
189
- }
190
-
191
- function startAutoRefresh() {
192
- setInterval(checkForUpdates, 1000);
193
- document.addEventListener('visibilitychange', function() {
194
- if (!document.hidden) {
195
- lastUpdate = Date.now() - 4900;
196
- }
197
- });
198
- }
199
-
200
- if (document.readyState === 'complete') {
201
- startAutoRefresh();
202
- } else {
203
- window.addEventListener('load', startAutoRefresh);
204
- }
205
- </script>
206
- """
207
- st.components.v1.html(refresh_html, height=0)
208
-
209
  def main():
210
  create_autorefresh()
211
  update_nearby_players()
@@ -228,14 +244,17 @@ def main():
228
  'HP': random.randint(1, 20) * 2 + random.randint(1, 20),
229
  'MAX_HP': 40,
230
  'score': 0,
231
- 'created_at': time.time()
232
  }
233
  save_player_state()
234
  st.rerun()
235
  else:
236
  st.sidebar.markdown("### Nearby Players")
237
  for player in st.session_state.nearby_players:
238
- st.sidebar.markdown(f"**{player['name']}** - {player['distance']} tiles away - {player['score']} pts")
 
 
 
239
 
240
  st.sidebar.markdown("### Movement Controls")
241
  move_cols = st.sidebar.columns(3)
@@ -255,7 +274,8 @@ def main():
255
 
256
  if st.sidebar.button("Clear Game State"):
257
  st.query_params.clear()
258
- clear_caches()
 
259
  st.rerun()
260
 
261
  st.title("Multiplayer Tile Game")
 
9
  import base64
10
  from io import BytesIO
11
  import numpy as np
12
+ from py_mp import CommandServer, CommandClient, ClientCommand, ServerSideServerCommand
13
+ from py_mp.commands import NetworkFlag
14
+ import threading
15
+ import queue
16
 
17
+ # ๐ŸŽฎ Game Constants
18
  GRID_WIDTH = 16
19
  GRID_HEIGHT = 9
20
  REFRESH_RATE = 5
21
  INTERACTION_RADIUS = 2
22
  POINTS_PER_INTERACTION = 1
23
 
24
+ # ๐ŸŒ Network Settings
25
+ SERVER_HOST = "localhost"
26
+ SERVER_PORT = 5000
27
+ message_queue = queue.Queue()
28
+
29
+ # โฐ Time Sync
30
+ def get_server_time():
31
+ return time.time()
32
+
33
+ # ๐ŸŽจ Resource Management
34
  @st.cache_resource(show_spinner="Loading game resources...")
35
  def get_game_images():
36
  return {
 
39
  'other_player': Image.new('RGB', (50, 50), color='red')
40
  }
41
 
42
+ # ๐Ÿ“ Name Generation
43
  @st.cache_data
44
  def get_name_components():
45
  return {
 
49
  'is', 'ax', 'on', 'ir', 'ex', 'az', 'er', 'eth', 'ys', 'ix']
50
  }
51
 
52
+ # ๐Ÿ”„ Player Synchronization
53
+ @st.cache_data(ttl=2)
54
  def load_all_players(timestamp):
55
  players = {}
56
  if os.path.exists('players'):
 
63
  players[player_data['name']] = player_data
64
  except json.JSONDecodeError:
65
  continue
66
+ return {'players': players, 'last_update': timestamp}
67
 
68
+ # ๐Ÿ”„ Auto-Refresh Implementation
69
+ def create_autorefresh():
70
+ refresh_html = """
71
+ <script>
72
+ let lastUpdate = Date.now();
73
+ let serverTimeOffset = 0;
74
+
75
+ async function syncTime() {
76
+ const response = await fetch('/server_time');
77
+ const serverTime = await response.json();
78
+ serverTimeOffset = serverTime - Date.now();
79
+ }
80
+
81
+ function getServerTime() {
82
+ return Date.now() + serverTimeOffset;
83
+ }
84
+
85
+ function checkForUpdates() {
86
+ const now = getServerTime();
87
+ if (now - lastUpdate >= 5000) {
88
+ lastUpdate = now;
89
+ window.parent.document.querySelector('.stApp').classList.add('refreshing');
90
+ setTimeout(() => window.location.reload(), 100);
91
+ }
92
+ }
93
 
94
+ function startAutoRefresh() {
95
+ syncTime();
96
+ setInterval(syncTime, 30000);
97
+ setInterval(checkForUpdates, 1000);
98
+
99
+ document.addEventListener('visibilitychange', function() {
100
+ if (!document.hidden) {
101
+ syncTime();
102
+ lastUpdate = getServerTime() - 4900;
103
+ }
104
+ });
105
+ }
106
 
107
+ if (document.readyState === 'complete') {
108
+ startAutoRefresh();
109
+ } else {
110
+ window.addEventListener('load', startAutoRefresh);
111
+ }
112
+ </script>
113
+ """
114
+ st.components.v1.html(refresh_html, height=0)
 
 
 
 
 
 
 
 
 
 
 
115
 
116
+ # ๐Ÿ’พ State Management
117
  def save_game_state():
118
  if st.session_state.player_name and st.session_state.character_stats:
119
  params = {
120
  'player_name': st.session_state.player_name,
121
  'x': str(st.session_state.position['x']),
122
  'y': str(st.session_state.position['y']),
123
+ **{k: str(v) for k, v in st.session_state.character_stats.items()},
124
+ 'last_sync': str(get_server_time())
125
  }
126
  st.query_params.from_dict(params)
127
 
128
+ # ๐ŸŽฒ Game State Initialization
129
  if 'initialized' not in st.session_state:
130
  st.session_state.initialized = False
131
  st.session_state.game_state = {
132
  'players': {},
133
  'chat_messages': [],
134
+ 'last_sync': get_server_time()
135
  }
136
  st.session_state.player_name = None
137
  st.session_state.character_stats = None
 
139
  'x': random.randint(0, GRID_WIDTH - 1),
140
  'y': random.randint(0, GRID_HEIGHT - 1)
141
  }
142
+ st.session_state.last_move = get_server_time()
143
  st.session_state.nearby_players = []
 
144
 
145
+ # ๐ŸŽฎ Player State Management
146
  def save_player_state():
147
  if st.session_state.player_name:
148
  player_data = {
149
  'name': st.session_state.player_name,
150
  'position': st.session_state.position,
151
  'stats': st.session_state.character_stats,
152
+ 'last_update': get_server_time()
153
  }
154
  os.makedirs('players', exist_ok=True)
155
  with open(f"players/{st.session_state.player_name}.json", 'w') as f:
156
  json.dump(player_data, f)
157
  save_game_state()
158
 
159
+ # ๐Ÿ“ Distance Calculation
160
  def calculate_distance(pos1, pos2):
161
  dx = min(abs(pos1['x'] - pos2['x']), GRID_WIDTH - abs(pos1['x'] - pos2['x']))
162
  dy = min(abs(pos1['y'] - pos2['y']), GRID_HEIGHT - abs(pos1['y'] - pos2['y']))
163
  return dx + dy
164
 
165
+ # ๐Ÿƒโ€โ™‚๏ธ Movement System
166
  def update_position(direction):
167
  if direction == "up":
168
  st.session_state.position['y'] = (st.session_state.position['y'] - 1) % GRID_HEIGHT
 
172
  st.session_state.position['x'] = (st.session_state.position['x'] - 1) % GRID_WIDTH
173
  elif direction == "right":
174
  st.session_state.position['x'] = (st.session_state.position['x'] + 1) % GRID_WIDTH
175
+ st.session_state.last_move = get_server_time()
176
  save_player_state()
177
 
178
+ # ๐Ÿ‘ฅ Nearby Players Update
179
  def update_nearby_players():
180
+ current_time = get_server_time()
181
  all_players = load_all_players(current_time)['players']
182
  nearby = []
183
  score_gain = 0
 
188
  nearby.append({
189
  'name': player_name,
190
  'distance': distance,
191
+ 'score': player_data['stats']['score'],
192
+ 'last_seen': current_time - player_data['last_update']
193
  })
194
  score_gain += POINTS_PER_INTERACTION
195
  if score_gain > 0:
 
197
  save_player_state()
198
  st.session_state.nearby_players = nearby
199
 
200
+ # ๐ŸŽจ Game Board Creation
201
  def create_game_board():
202
+ current_time = get_server_time()
203
  all_players = load_all_players(current_time)['players']
204
  images = get_game_images()
205
+
206
  for y in range(GRID_HEIGHT):
207
  cols = st.columns(GRID_WIDTH)
208
  for x in range(GRID_WIDTH):
 
211
  if (player_data['position']['x'] == x and
212
  player_data['position']['y'] == y):
213
  player_here = player_name
214
+
215
  if x == st.session_state.position['x'] and y == st.session_state.position['y']:
216
  cols[x].image(images['player'], use_column_width=True)
217
  cols[x].markdown(f"**You** ({st.session_state.character_stats['score']} pts)")
 
221
  else:
222
  cols[x].image(images['tile'], use_column_width=True)
223
 
224
+ # ๐ŸŽฎ Main Game Loop
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  def main():
226
  create_autorefresh()
227
  update_nearby_players()
 
244
  'HP': random.randint(1, 20) * 2 + random.randint(1, 20),
245
  'MAX_HP': 40,
246
  'score': 0,
247
+ 'created_at': get_server_time()
248
  }
249
  save_player_state()
250
  st.rerun()
251
  else:
252
  st.sidebar.markdown("### Nearby Players")
253
  for player in st.session_state.nearby_players:
254
+ st.sidebar.markdown(
255
+ f"**{player['name']}** - {player['distance']} tiles away - {player['score']} pts\n"
256
+ f"Last seen: {player['last_seen']:.1f}s ago"
257
+ )
258
 
259
  st.sidebar.markdown("### Movement Controls")
260
  move_cols = st.sidebar.columns(3)
 
274
 
275
  if st.sidebar.button("Clear Game State"):
276
  st.query_params.clear()
277
+ st.cache_resource.clear()
278
+ st.cache_data.clear()
279
  st.rerun()
280
 
281
  st.title("Multiplayer Tile Game")