Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import os | |
| import json | |
| import random | |
| from huggingface_hub import InferenceClient | |
| # --- CONFIGURATION --- | |
| # Connects to Hugging Face's Free Inference API | |
| # You must set 'HF_TOKEN' in your Space Settings (Variables and secrets) | |
| HF_TOKEN = os.getenv("HF_TOKEN") | |
| # --- BRANDING & ASSETS --- | |
| COMPANY_NAME = "SpeedoDude" | |
| APP_TITLE = f"π {COMPANY_NAME} AI Game Architect" | |
| DONATION_HTML = """ | |
| <div align="center"> | |
| <p><b>Support {company} Development</b><br> | |
| OmniMod is free and open source. If this tool helped you, please consider donating!</p> | |
| <a href="https://www.patreon.com/YOUR_USERNAME" target="_blank"> | |
| <img src="https://img.shields.io/badge/Support_on-Patreon-f96854?style=for-the-badge&logo=patreon&logoColor=white" alt="Support on Patreon"/> | |
| </a> | |
| <a href="https://ko-fi.com/YOUR_USERNAME" target="_blank"> | |
| <img src="https://img.shields.io/badge/Buy_me_a-Coffee-ff5f5f?style=for-the-badge&logo=ko-fi&logoColor=white" alt="Buy me a Coffee"/> | |
| </a> | |
| </div> | |
| """.format(company=COMPANY_NAME) | |
| LEGAL_TEXT = """ | |
| ### β οΈ Legal Disclaimer & Terms | |
| 1. **Single-Player Only:** This tool is strictly for offline, creative use. Do not use in multiplayer environments. | |
| 2. **Liability:** SpeedoDude is not responsible for account bans or data loss. Always backup your save files. | |
| 3. **Ownership:** Assets generated via the SpeedoDude Generator belong to you, the user. | |
| """ | |
| # ============================================================================== | |
| # MODULE 1: THE GENERATOR (Assets & Textures) | |
| # ============================================================================== | |
| def generate_asset(prompt, style, asset_type): | |
| """ | |
| Generates game textures/concepts using Stable Diffusion. | |
| """ | |
| if not HF_TOKEN: | |
| return None, "β οΈ Error: HF_TOKEN secret is missing in Space Settings." | |
| # Model Selection: Stable Diffusion 2.1 is reliable and free on HF | |
| model_id = "stabilityai/stable-diffusion-2-1" | |
| client = InferenceClient(model_id, token=HF_TOKEN) | |
| # Optimized Prompt Engineering | |
| full_prompt = f"{prompt}, {style} style, {asset_type} game asset, high quality, 4k, flat lighting, seamless" | |
| try: | |
| image = client.text_to_image(full_prompt) | |
| output_path = "/tmp/speedodude_asset.png" | |
| image.save(output_path) | |
| return output_path, f"β Success! Generated: '{full_prompt}'" | |
| except Exception as e: | |
| return None, f"β Generation Error: {str(e)}" | |
| # ============================================================================== | |
| # MODULE 2: THE FABRICATOR (Save File Editor) | |
| # ============================================================================== | |
| def analyze_save_file(file_obj): | |
| """ | |
| Reads a .json or .xml file and shows the structure. | |
| """ | |
| if file_obj is None: return "Please upload a file first." | |
| try: | |
| with open(file_obj.name, 'r') as f: | |
| content = f.read() | |
| # Try parsing JSON | |
| try: | |
| data = json.loads(content) | |
| keys = list(data.keys())[:50] # Preview first 50 keys | |
| return f"π File Valid (JSON).\nFound Top-Level Keys:\n{keys}..." | |
| except json.JSONDecodeError: | |
| # Fallback for XML/Text (Basic preview) | |
| return f"π File Valid (Text/XML).\nPreview:\n{content[:500]}..." | |
| except Exception as e: | |
| return f"β Error reading file: {str(e)}" | |
| def apply_hack(file_obj, key_to_find, new_value): | |
| """ | |
| Recursively searches a JSON file for a specific key and updates it. | |
| """ | |
| if file_obj is None: return None, "Upload a file first." | |
| try: | |
| with open(file_obj.name, 'r') as f: | |
| data = json.load(f) | |
| matches = 0 | |
| def update_recursive(d, target_k, target_v): | |
| nonlocal matches | |
| for k in d: | |
| if k == target_k: | |
| # Smart Type Conversion (Maintain Int/Float/String) | |
| if isinstance(d[k], int): | |
| d[k] = int(target_v) | |
| elif isinstance(d[k], float): | |
| d[k] = float(target_v) | |
| else: | |
| d[k] = str(target_v) | |
| matches += 1 | |
| elif isinstance(d[k], dict): | |
| update_recursive(d[k], target_k, target_v) | |
| elif isinstance(d[k], list): | |
| for item in d[k]: | |
| if isinstance(item, dict): | |
| update_recursive(item, target_k, target_v) | |
| update_recursive(data, key_to_find, new_value) | |
| if matches == 0: | |
| return None, f"β οΈ Key '{key_to_find}' not found in file." | |
| output_path = "/tmp/speedodude_modded.json" | |
| with open(output_path, 'w') as f: | |
| json.dump(data, f, indent=4) | |
| return output_path, f"β Success! Updated {matches} instance(s) of '{key_to_find}'." | |
| except Exception as e: | |
| return None, f"β Error: {str(e)}" | |
| # ============================================================================== | |
| # MODULE 3: THE ARCHITECT (Alchemist, Dojo, Director, Genesis) | |
| # ============================================================================== | |
| def generate_blueprint(blueprint_type, name, details): | |
| """ | |
| Generates code snippets and configuration files for various game systems. | |
| Combines Alchemist (Items), Dojo (Combat), Director (Scenes), Genesis (Project). | |
| """ | |
| name_clean = name.replace(" ", "") | |
| # --- ALCHEMIST (Custom Items) --- | |
| if blueprint_type == "Item Script (Unity C#)": | |
| return f"""// Generated by SpeedoDude Alchemist | |
| using UnityEngine; | |
| [CreateAssetMenu(fileName = "{name}", menuName = "SpeedoDude/Item")] | |
| public class {name_clean} : ItemObject {{ | |
| public string itemName = "{name}"; | |
| [TextArea] public string description = "{details}"; | |
| public override void OnUse(Character user) {{ | |
| Debug.Log("Using {name}..."); | |
| // Effect Logic: {details} | |
| // TODO: Implement specific stat changes here. | |
| }} | |
| }} | |
| """ | |
| # --- DOJO (Combat Logic) --- | |
| elif blueprint_type == "Combat Style (JSON)": | |
| data = { | |
| "style_name": name, | |
| "description": details, | |
| "creator": COMPANY_NAME, | |
| "moves": [ | |
| {"name": "Light Attack", "damage": 10, "anim": f"{name}_Light.anim", "frame_data": 5}, | |
| {"name": "Heavy Attack", "damage": 25, "anim": f"{name}_Heavy.anim", "frame_data": 15}, | |
| {"name": "Special", "damage": 50, "effect": details} | |
| ] | |
| } | |
| return json.dumps(data, indent=4) | |
| # --- DIRECTOR (Scene Layout) --- | |
| elif blueprint_type == "Scene Layout (JSON)": | |
| return json.dumps({ | |
| "scene_name": name, | |
| "theme": details, | |
| "lighting": {"ambient": "#1a1a1a", "sun_intensity": 0.8}, | |
| "objects": [ | |
| {"id": "player_start", "pos": [0, 1, 0]}, | |
| {"id": "enemy_spawn", "pos": [10, 0, 5]}, | |
| {"id": "prop_chest", "pos": [-5, 0, 2], "loot": "random"} | |
| ] | |
| }, indent=4) | |
| # --- GENESIS (Unreal Project Config) --- | |
| elif blueprint_type == "Unreal Project File (.uproject)": | |
| return json.dumps({ | |
| "FileVersion": 3, | |
| "EngineAssociation": "5.3", | |
| "Category": "", | |
| "Description": f"{details} - Generated by SpeedoDude Genesis", | |
| "Modules": [ | |
| {"Name": name_clean, "Type": "Runtime", "LoadingPhase": "Default"} | |
| ] | |
| }, indent=4) | |
| return "Error: Unknown Blueprint Type" | |
| # ============================================================================== | |
| # MAIN UI LAYOUT | |
| # ============================================================================== | |
| # Using 'Soft' theme with SpeedoDude colors | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="cyan", secondary_hue="indigo"), title=APP_TITLE) as app: | |
| # --- HEADER --- | |
| gr.Markdown(f"# {APP_TITLE}") | |
| gr.Markdown("The ultimate cloud-based suite for single-player game modding.") | |
| gr.HTML(DONATION_HTML) # Inject Donation Badges | |
| # --- TABS --- | |
| with gr.Tabs(): | |
| # TAB 1: GENERATOR | |
| with gr.TabItem("π¨ Generator"): | |
| gr.Markdown("### Create Game Assets") | |
| with gr.Row(): | |
| gen_prompt = gr.Textbox(label="Prompt", placeholder="A rusty cyber-sword with glowing green edges") | |
| gen_style = gr.Dropdown(["Realistic", "Pixel Art", "Sci-Fi", "Fantasy", "Cartoon"], label="Style", value="Realistic") | |
| gen_type = gr.Dropdown(["Icon", "Texture", "Concept Art", "UI Element"], label="Type", value="Texture") | |
| gen_btn = gr.Button("Generate Asset", variant="primary") | |
| with gr.Row(): | |
| gen_image = gr.Image(label="Result") | |
| gen_log = gr.Textbox(label="System Log") | |
| gen_btn.click(generate_asset, inputs=[gen_prompt, gen_style, gen_type], outputs=[gen_image, gen_log]) | |
| # TAB 2: FABRICATOR | |
| with gr.TabItem("πΎ Fabricator"): | |
| gr.Markdown("### Save File Editor") | |
| with gr.Row(): | |
| file_input = gr.File(label="Upload Save (.json)") | |
| analyze_btn = gr.Button("Analyze File") | |
| file_info = gr.Textbox(label="File Structure Preview", lines=4) | |
| analyze_btn.click(analyze_save_file, inputs=file_input, outputs=file_info) | |
| gr.Markdown("---") | |
| gr.Markdown("### Apply Modification") | |
| with gr.Row(): | |
| hack_key = gr.Textbox(label="Key to Change", placeholder="e.g., gold, health, xp") | |
| hack_val = gr.Textbox(label="New Value", placeholder="999999") | |
| hack_btn = gr.Button("Apply Hack", variant="stop") | |
| with gr.Row(): | |
| hack_download = gr.File(label="Download Modded Save") | |
| hack_log = gr.Textbox(label="System Log") | |
| hack_btn.click(apply_hack, inputs=[file_input, hack_key, hack_val], outputs=[hack_download, hack_log]) | |
| # TAB 3: ARCHITECT (Alchemist/Dojo/Director/Genesis) | |
| with gr.TabItem("π Architect"): | |
| gr.Markdown("### Code & Blueprint Generator") | |
| gr.Markdown("Generate production-ready scripts for Unity/Unreal.") | |
| with gr.Row(): | |
| arch_type = gr.Dropdown([ | |
| "Item Script (Unity C#)", | |
| "Combat Style (JSON)", | |
| "Scene Layout (JSON)", | |
| "Unreal Project File (.uproject)" | |
| ], label="Blueprint Type") | |
| arch_name = gr.Textbox(label="Name", placeholder="Excalibur / CyberArena") | |
| arch_details = gr.Textbox(label="Description / Effect / Theme", placeholder="High damage sword that heals on hit...") | |
| arch_btn = gr.Button("Generate Blueprint", variant="primary") | |
| arch_output = gr.Code(label="Generated Output", language="csharp") | |
| arch_btn.click(generate_blueprint, inputs=[arch_type, arch_name, arch_details], outputs=arch_output) | |
| # --- FOOTER --- | |
| gr.Markdown("---") | |
| gr.Markdown(LEGAL_TEXT) | |
| gr.Markdown(f"Β© 2025 {COMPANY_NAME}. All Rights Reserved.") | |
| # ============================================================================== | |
| # LAUNCHER (MCP ENABLED) | |
| # ============================================================================== | |
| if __name__ == "__main__": | |
| # mcp=True enables Claude/Cursor to control this app as a server | |
| app.launch(mcp=True) | |