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 = """

Support {company} Development
OmniMod is free and open source. If this tool helped you, please consider donating!

Support on Patreon Buy me a Coffee
""".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)