File size: 5,603 Bytes
41c1a97
 
55e0bb5
689ff91
 
41c1a97
55e0bb5
bcaa97a
434590c
55e0bb5
 
bcaa97a
55e0bb5
 
 
 
 
 
d9c5a9e
55e0bb5
 
d9c5a9e
55e0bb5
a2141e7
55e0bb5
 
a2141e7
55e0bb5
 
a2141e7
55e0bb5
a2141e7
55e0bb5
 
a2141e7
55e0bb5
a2141e7
55e0bb5
 
 
50498a4
55e0bb5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7825ef7
 
55e0bb5
d9c5a9e
55e0bb5
 
 
 
 
 
 
 
 
 
 
 
b704ae5
 
 
55e0bb5
 
b704ae5
55e0bb5
 
 
 
b704ae5
 
 
55e0bb5
 
 
 
 
 
 
 
 
 
7825ef7
f32aedf
55e0bb5
 
 
 
 
 
 
a2141e7
55e0bb5
 
434590c
55e0bb5
434590c
55e0bb5
434590c
55e0bb5
7825ef7
55e0bb5
7825ef7
89b923d
7825ef7
55e0bb5
 
 
4fa9b7a
 
55e0bb5
 
89b923d
55e0bb5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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}")