awacke1's picture
Update app.py
55e0bb5 verified
raw
history blame
5.6 kB
# app.py
import streamlit as st
# st.set_page_config MUST be the first Streamlit command
st.set_page_config(page_title="Infinite World Builder", layout="wide")
import streamlit.components.v1 as components
import os, json, time, uuid, math
from datetime import datetime
# --- Global State File ---
GLOBAL_STATE_FILE = "global_state.json"
# If the global state file does not exist, create it with an empty state.
if not os.path.exists(GLOBAL_STATE_FILE):
empty_state = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"game_state": [], # List of object records
"player_position": {"x": 0, "y": 0, "z": 0}
}
with open(GLOBAL_STATE_FILE, "w", encoding="utf-8") as f:
json.dump(empty_state, f, indent=2)
def load_global_state():
try:
with open(GLOBAL_STATE_FILE, "r", encoding="utf-8") as f:
return json.load(f)
except Exception as e:
st.error(f"Error loading global state: {e}")
return {"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), "game_state": [], "player_position": {"x":0, "y":0, "z":0}}
def save_global_state(state):
try:
with open(GLOBAL_STATE_FILE, "w", encoding="utf-8") as f:
json.dump(state, f, indent=2)
except Exception as e:
st.error(f"Error saving global state: {e}")
# --- Initialize global state in session_state ---
if "global_state" not in st.session_state:
st.session_state["global_state"] = load_global_state()
# --- Utility: Update Global State with New Objects ---
def add_objects_to_global(new_objects, player_position):
"""
Merge new object records into the global state.
Each object is expected to have a unique 'obj_id'. If not, one is generated.
"""
state = st.session_state["global_state"]
# Create dictionary of existing objects by obj_id
existing = {obj["obj_id"]: obj for obj in state.get("game_state", []) if "obj_id" in obj}
for obj in new_objects:
obj_id = obj.get("obj_id", str(uuid.uuid4()))
obj["obj_id"] = obj_id
existing[obj_id] = obj
state["game_state"] = list(existing.values())
# Update player position and timestamp (for simplicity, overwrite with latest)
state["player_position"] = player_position
state["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
st.session_state["global_state"] = state
save_global_state(state)
# --- Sidebar Controls ---
with st.sidebar:
st.title("๐Ÿ—๏ธ World Controls")
# Button to force reload global state from file.
if st.button("๐Ÿ”„ Reload Global State"):
st.session_state["global_state"] = load_global_state()
st.success("Global state reloaded.")
# Button to clear the global state.
if st.button("๐Ÿ—‘๏ธ Clear Global State"):
empty = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"game_state": [],
"player_position": {"x": 0, "y": 0, "z": 0}
}
st.session_state["global_state"] = empty
save_global_state(empty)
st.success("Global state cleared.")
st.markdown("---")
st.header("Download Global Save as Markdown")
state = st.session_state["global_state"]
default_md_name = state.get("timestamp", "save").replace(":", "").replace(" ", "_") + ".md"
download_name = st.text_input("Override File Name", value=default_md_name)
md_outline = f"""# Global Save: {download_name}
- โฐ **Timestamp:** {state.get("timestamp", "N/A")}
- ๐ŸŽฎ **Number of Game Objects:** {len(state.get("game_state", []))}
- ๐Ÿงญ **Player Position:** {state.get("player_position", {"x":0, "y":0, "z":0})}
## Game Objects:
"""
for i, obj in enumerate(state.get("game_state", []), start=1):
obj_type = obj.get("type", "Unknown")
pos = (obj.get("x", 0), obj.get("y", 0), obj.get("z", 0))
md_outline += f"- {i}. โœจ **{obj_type}** at {pos}\n"
st.download_button("Download Markdown Save", data=md_outline, file_name=download_name, mime="text/markdown")
# --- Process Save Data from JavaScript ---
# The JS component will set st.session_state["js_save_data"] to a JSON string when an object is placed.
save_data_from_js = st.session_state.get("js_save_data", None)
if save_data_from_js:
try:
payload = json.loads(save_data_from_js) if isinstance(save_data_from_js, str) else save_data_from_js
if isinstance(payload, dict) and "playerPosition" in payload and "objectsToSave" in payload:
player_pos = payload["playerPosition"]
objects = payload["objectsToSave"]
add_objects_to_global(objects, player_pos)
st.success("Global state updated with new objects.")
st.session_state["js_save_data"] = None
st.experimental_rerun()
except Exception as e:
st.error(f"Error processing JS save data: {e}")
st.session_state["js_save_data"] = None
# --- Inject Global State into JavaScript ---
injected_state = {
"GLOBAL_STATE": st.session_state["global_state"]
}
html_file_path = "index.html"
try:
with open(html_file_path, "r", encoding="utf-8") as f:
html_template = f.read()
js_injection_script = f"""
<script>
// Inject the global state from Streamlit into the web app.
window.GLOBAL_STATE = {json.dumps(injected_state["GLOBAL_STATE"])};
console.log("Injected Global State:", window.GLOBAL_STATE);
</script>
"""
html_content = html_template.replace("</head>", js_injection_script + "\n</head>", 1)
components.html(html_content, height=750, scrolling=True)
except Exception as e:
st.error(f"Error loading index.html: {e}")