awacke1 commited on
Commit
bb2022a
·
verified ·
1 Parent(s): 033fbe6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +16 -171
app.py CHANGED
@@ -7,7 +7,7 @@ import uuid # 🆔 Unique IDs
7
  import math # ➗ Math utils
8
  import time # ⏳ Time utilities
9
 
10
- from gamestate import GameState # 💼 Shared game-state singleton
11
 
12
  # 🚀 Page setup
13
  st.set_page_config(page_title="Infinite World Builder", layout="wide")
@@ -25,110 +25,7 @@ CSV_COLUMNS = [
25
  # 🗂️ Ensure directory for plots exists
26
  os.makedirs(SAVE_DIR, exist_ok=True)
27
 
28
- @st.cache_data(ttl=3600) # 🕒 Cache for 1h
29
- def load_plot_metadata():
30
- # 🔍 Scan SAVE_DIR for plot CSVs
31
- try:
32
- plot_files = [f for f in os.listdir(SAVE_DIR)
33
- if f.endswith(".csv") and f.startswith("plot_X")]
34
- except FileNotFoundError:
35
- st.error(f"Folder '{SAVE_DIR}' missing! 🚨")
36
- return []
37
- except Exception as e:
38
- st.error(f"Error reading '{SAVE_DIR}': {e}")
39
- return []
40
-
41
- parsed = []
42
- for fn in plot_files:
43
- try:
44
- parts = fn[:-4].split('_') # strip .csv
45
- gx = int(parts[1][1:]) # X index
46
- gz = int(parts[2][1:]) # Z index
47
- name = " ".join(parts[3:]) if len(parts)>3 else f"Plot({gx},{gz})"
48
- parsed.append({
49
- 'id': fn[:-4],
50
- 'filename': fn,
51
- 'grid_x': gx,
52
- 'grid_z': gz,
53
- 'name': name,
54
- 'x_offset': gx * PLOT_WIDTH,
55
- 'z_offset': gz * PLOT_DEPTH
56
- })
57
- except Exception:
58
- st.warning(f"Skip invalid file: {fn}")
59
- parsed.sort(key=lambda p: (p['grid_x'], p['grid_z']))
60
- return parsed
61
-
62
-
63
- def load_plot_objects(filename, x_offset, z_offset):
64
- # 📥 Load objects from a plot CSV and shift by offsets
65
- path = os.path.join(SAVE_DIR, filename)
66
- try:
67
- df = pd.read_csv(path)
68
- # 🛡️ Ensure essentials exist
69
- if not all(c in df.columns for c in ['type','pos_x','pos_y','pos_z']):
70
- st.warning(f"Missing cols in {filename} 🧐")
71
- return []
72
- # 🆔 Guarantee obj_id
73
- df['obj_id'] = df.get('obj_id', pd.Series([str(uuid.uuid4()) for _ in df.index]))
74
- # 🔄 Fill missing rotation
75
- for col, default in [('rot_x',0.0),('rot_y',0.0),('rot_z',0.0),('rot_order','XYZ')]:
76
- if col not in df.columns:
77
- df[col] = default
78
-
79
- objs = []
80
- for _, row in df.iterrows():
81
- o = row.to_dict()
82
- o['pos_x'] += x_offset
83
- o['pos_z'] += z_offset
84
- objs.append(o)
85
- return objs
86
- except FileNotFoundError:
87
- st.error(f"CSV not found: {filename}")
88
- return []
89
- except pd.errors.EmptyDataError:
90
- return []
91
- except Exception as e:
92
- st.error(f"Load error {filename}: {e}")
93
- return []
94
-
95
-
96
- def save_plot_data(filename, objects_list, px, pz):
97
- # 💾 Save list of new objects relative to plot origin
98
- path = os.path.join(SAVE_DIR, filename)
99
- if not isinstance(objects_list, list):
100
- st.error("👎 Invalid data format for save")
101
- return False
102
-
103
- rel = []
104
- for o in objects_list:
105
- pos = o.get('position', {})
106
- rot = o.get('rotation', {})
107
- typ = o.get('type','Unknown')
108
- oid = o.get('obj_id', str(uuid.uuid4()))
109
- # 🛑 Skip bad objects
110
- if not all(k in pos for k in ['x','y','z']) or typ=='Unknown':
111
- continue
112
- rel.append({
113
- 'obj_id': oid, 'type': typ,
114
- 'pos_x': pos['x']-px, 'pos_y': pos['y'], 'pos_z': pos['z']-pz,
115
- 'rot_x': rot.get('_x',0.0), 'rot_y': rot.get('_y',0.0),
116
- 'rot_z': rot.get('_z',0.0), 'rot_order': rot.get('_order','XYZ')
117
- })
118
- try:
119
- pd.DataFrame(rel, columns=CSV_COLUMNS).to_csv(path, index=False)
120
- st.success(f"🎉 Saved {len(rel)} to {filename}")
121
- return True
122
- except Exception as e:
123
- st.error(f"Save failed: {e}")
124
- return False
125
-
126
- # 🔒 Singleton for global world state
127
- @st.cache_resource
128
- def get_game_state():
129
- return GameState(save_dir=SAVE_DIR, csv_filename="world_state.csv")
130
-
131
- game_state = get_game_state()
132
 
133
  # 🧠 Session state defaults
134
  st.session_state.setdefault('selected_object','None')
@@ -160,7 +57,19 @@ with st.sidebar:
160
 
161
  st.markdown("---")
162
  st.header("🌲 Place Objects")
163
- opts = ["None","Simple House","Tree","Rock","Fence Post"]
 
 
 
 
 
 
 
 
 
 
 
 
164
  idx = opts.index(st.session_state.selected_object) if st.session_state.selected_object in opts else 0
165
  sel = st.selectbox("Select:", opts, index=idx, key="selected_object_widget")
166
  if sel != st.session_state.selected_object:
@@ -173,68 +82,4 @@ with st.sidebar:
173
  streamlit_js_eval(js_code="getSaveDataAndPosition();", key="js_save_processor")
174
  st.rerun()
175
 
176
- # 📨 Handle incoming save data
177
- raw = st.session_state.get("js_save_processor")
178
- if raw:
179
- st.info("📬 Got save data!")
180
- ok=False
181
- try:
182
- pay = json.loads(raw) if isinstance(raw,str) else raw
183
- pos, objs = pay.get('playerPosition'), pay.get('objectsToSave')
184
- if isinstance(objs,list) and pos:
185
- gx, gz = math.floor(pos['x']/PLOT_WIDTH), math.floor(pos['z']/PLOT_DEPTH)
186
- fn = f"plot_X{gx}_Z{gz}.csv"
187
- if save_plot_data(fn, objs, gx*PLOT_WIDTH, gz*PLOT_DEPTH):
188
- load_plot_metadata.clear()
189
- try:
190
- from streamlit_js_eval import streamlit_js_eval
191
- streamlit_js_eval(js_code="resetNewlyPlacedObjects();", key="reset_js")
192
- except:
193
- pass
194
- game_state.update_state(objs)
195
- ok=True
196
- if not ok:
197
- st.error("❌ Save error")
198
- except Exception as e:
199
- st.error(f"Err: {e}")
200
- st.session_state.js_save_processor=None
201
- if ok: st.rerun()
202
-
203
- # 🏠 Main view
204
- st.header("🌍 Infinite Shared 3D World")
205
- st.caption("➡️ Explore, click to build, 💾 to save!")
206
-
207
- # 🔌 Inject state into JS
208
- state = {
209
- "ALL_INITIAL_OBJECTS": all_initial_objects,
210
- "PLOTS_METADATA": plots_metadata,
211
- "SELECTED_OBJECT_TYPE": st.session_state.selected_object,
212
- "PLOT_WIDTH": PLOT_WIDTH,
213
- "PLOT_DEPTH": PLOT_DEPTH,
214
- "GAME_STATE": game_state.get_state()
215
- }
216
-
217
- try:
218
- with open('index.html','r',encoding='utf-8') as f:
219
- html = f.read()
220
- script = f"""
221
- <script>
222
- window.ALL_INITIAL_OBJECTS = {json.dumps(state['ALL_INITIAL_OBJECTS'])};
223
- window.PLOTS_METADATA = {json.dumps(state['PLOTS_METADATA'])};
224
- window.SELECTED_OBJECT_TYPE = {json.dumps(state['SELECTED_OBJECT_TYPE'])};
225
- window.PLOT_WIDTH = {json.dumps(state['PLOT_WIDTH'])};
226
- window.PLOT_DEPTH = {json.dumps(state['PLOT_DEPTH'])};
227
- window.GAME_STATE = {json.dumps(state['GAME_STATE'])};
228
- console.log('👍 State injected!', {{
229
- objs: window.ALL_INITIAL_OBJECTS.length,
230
- plots: window.PLOTS_METADATA.length,
231
- gs: window.GAME_STATE.length
232
- }});
233
- </script>
234
- """
235
- html = html.replace('</head>', script + '\n</head>', 1)
236
- components.html(html, height=750, scrolling=False)
237
- except FileNotFoundError:
238
- st.error("❌ index.html missing!")
239
- except Exception as e:
240
- st.error(f"😱 HTML inject failed: {e}")
 
7
  import math # ➗ Math utils
8
  import time # ⏳ Time utilities
9
 
10
+ from gamestate import GameState # 💼 Shared gamestate singleton
11
 
12
  # 🚀 Page setup
13
  st.set_page_config(page_title="Infinite World Builder", layout="wide")
 
25
  # 🗂️ Ensure directory for plots exists
26
  os.makedirs(SAVE_DIR, exist_ok=True)
27
 
28
+ # your existing load_plot_metadata, load_plot_objects, save_plot_data, GameState, etc. …
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  # 🧠 Session state defaults
31
  st.session_state.setdefault('selected_object','None')
 
57
 
58
  st.markdown("---")
59
  st.header("🌲 Place Objects")
60
+
61
+ # ←─── HERE: add your four builder‐tool options ────→
62
+ opts = [
63
+ "None",
64
+ "Simple House",
65
+ "Tree",
66
+ "Rock",
67
+ "Fence Post",
68
+ "Cyberpunk City Builder Kit",
69
+ "POLYGON - Fantasy Kingdom Pack",
70
+ "HEROIC FANTASY CREATURES FULL PACK VOL 1",
71
+ "POLYGON - Apocalypse Pack"
72
+ ]
73
  idx = opts.index(st.session_state.selected_object) if st.session_state.selected_object in opts else 0
74
  sel = st.selectbox("Select:", opts, index=idx, key="selected_object_widget")
75
  if sel != st.session_state.selected_object:
 
82
  streamlit_js_eval(js_code="getSaveDataAndPosition();", key="js_save_processor")
83
  st.rerun()
84
 
85
+ # the rest of your existing handler for save, and main view injection …