aethex-studio/store/editor-store.ts

191 lines
9.7 KiB
TypeScript

import { create } from 'zustand';
export interface FileNode {
id: string;
name: string;
type: 'file' | 'folder';
path: string;
children?: FileNode[];
platform?: 'roblox' | 'web' | 'mobile' | 'desktop' | 'shared';
content?: string;
}
export interface OpenFile {
id: string;
name: string;
path: string;
content: string;
language: string;
isDirty: boolean;
}
interface EditorStore {
files: FileNode[];
openFiles: OpenFile[];
activeFileId: string | null;
isSaving: boolean;
setFiles: (files: FileNode[]) => void;
openFile: (file: FileNode) => void;
closeFile: (fileId: string) => void;
setActiveFile: (fileId: string) => void;
updateFileContent: (fileId: string, content: string) => void;
saveFile: (fileId: string) => void;
saveAllFiles: () => void;
}
export const useEditorStore = create<EditorStore>((set, get) => ({
files: [
{
id: 'roblox',
name: 'roblox',
type: 'folder',
path: '/roblox',
platform: 'roblox',
children: [
{ id: 'roblox-main', name: 'main.lua', type: 'file', path: '/roblox/main.lua', platform: 'roblox', content: '-- Roblox Main Script\nprint("Hello from Roblox!")\n\n-- Player joined event\ngame.Players.PlayerAdded:Connect(function(player)\n print(player.Name .. " joined the game!")\nend)' },
{ id: 'roblox-controller', name: 'player-controller.lua', type: 'file', path: '/roblox/player-controller.lua', platform: 'roblox', content: '-- Player Controller\nlocal UserInputService = game:GetService("UserInputService")\n\nlocal function onInput(input, gameProcessed)\n if gameProcessed then return end\n -- Handle input\nend\n\nUserInputService.InputBegan:Connect(onInput)' },
{ id: 'roblox-datastore', name: 'datastore.lua', type: 'file', path: '/roblox/datastore.lua', platform: 'roblox', content: '-- DataStore Manager\nlocal DataStoreService = game:GetService("DataStoreService")\nlocal playerData = DataStoreService:GetDataStore("PlayerData")\n\nlocal function savePlayerData(player, data)\n -- Save data logic\nend' },
],
},
{
id: 'web',
name: 'web',
type: 'folder',
path: '/web',
platform: 'web',
children: [
{ id: 'web-index', name: 'index.html', type: 'file', path: '/web/index.html', platform: 'web', content: '<!DOCTYPE html>\n<html>\n<head>\n <title>AeThex Game</title>\n <link rel="stylesheet" href="style.css">\n</head>\n<body>\n <canvas id="game-canvas"></canvas>\n <script src="game.js"></script>\n</body>\n</html>' },
{ id: 'web-game', name: 'game.js', type: 'file', path: '/web/game.js', platform: 'web', content: '// Web Game Entry Point\nconst canvas = document.getElementById("game-canvas");\nconst ctx = canvas.getContext("2d");\n\nfunction gameLoop() {\n // Update game state\n // Render game\n requestAnimationFrame(gameLoop);\n}\n\ngameLoop();' },
{ id: 'web-style', name: 'style.css', type: 'file', path: '/web/style.css', platform: 'web', content: 'body {\n margin: 0;\n padding: 0;\n overflow: hidden;\n background: #000;\n}\n\n#game-canvas {\n display: block;\n width: 100%;\n height: 100vh;\n}' },
],
},
{
id: 'mobile',
name: 'mobile',
type: 'folder',
path: '/mobile',
platform: 'mobile',
children: [
{ id: 'mobile-app', name: 'App.tsx', type: 'file', path: '/mobile/App.tsx', platform: 'mobile', content: 'import React from "react";\nimport { GameScreen } from "./GameScreen";\n\nexport default function App() {\n return <GameScreen />;\n}' },
{ id: 'mobile-game', name: 'GameScreen.tsx', type: 'file', path: '/mobile/GameScreen.tsx', platform: 'mobile', content: 'import React from "react";\nimport { View, Text, StyleSheet } from "react-native";\n\nexport function GameScreen() {\n return (\n <View style={styles.container}>\n <Text>Mobile Game</Text>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: { flex: 1, justifyContent: "center", alignItems: "center" },\n});' },
{ id: 'mobile-config', name: 'config.json', type: 'file', path: '/mobile/config.json', platform: 'mobile', content: '{\n "name": "AeThexGame",\n "displayName": "AeThex Game",\n "version": "1.0.0",\n "platforms": ["ios", "android"]\n}' },
],
},
{
id: 'desktop',
name: 'desktop',
type: 'folder',
path: '/desktop',
platform: 'desktop',
children: [
{ id: 'desktop-main', name: 'main.js', type: 'file', path: '/desktop/main.js', platform: 'desktop', content: '// Electron Main Process\nconst { app, BrowserWindow } = require("electron");\n\nfunction createWindow() {\n const win = new BrowserWindow({\n width: 1280,\n height: 720,\n webPreferences: {\n preload: __dirname + "/preload.js"\n }\n });\n win.loadFile("index.html");\n}\n\napp.whenReady().then(createWindow);' },
{ id: 'desktop-preload', name: 'preload.js', type: 'file', path: '/desktop/preload.js', platform: 'desktop', content: '// Electron Preload Script\nconst { contextBridge } = require("electron");\n\ncontextBridge.exposeInMainWorld("electronAPI", {\n platform: "desktop",\n version: "1.0.0"\n});' },
],
},
{
id: 'shared',
name: 'shared',
type: 'folder',
path: '/shared',
platform: 'shared',
children: [
{ id: 'shared-nexus', name: 'nexus-engine.ts', type: 'file', path: '/shared/nexus-engine.ts', platform: 'shared', content: '// Nexus Engine - Cross-Platform State Sync\nexport class NexusEngine {\n private state: Map<string, any> = new Map();\n private listeners: Set<Function> = new Set();\n\n setState(key: string, value: any) {\n this.state.set(key, value);\n this.broadcast(key, value);\n }\n\n getState(key: string) {\n return this.state.get(key);\n }\n\n private broadcast(key: string, value: any) {\n this.listeners.forEach(listener => listener(key, value));\n }\n}' },
{ id: 'shared-passport', name: 'passport-auth.ts', type: 'file', path: '/shared/passport-auth.ts', platform: 'shared', content: '// Passport - Unified Authentication\nexport class PassportAuth {\n private token: string | null = null;\n\n async login(username: string, password: string) {\n // Mock login\n this.token = "mock-token-" + username;\n return { success: true, token: this.token };\n }\n\n async logout() {\n this.token = null;\n }\n\n isAuthenticated() {\n return this.token !== null;\n }\n}' },
{ id: 'shared-config', name: 'gameforge-config.json', type: 'file', path: '/shared/gameforge-config.json', platform: 'shared', content: '{\n "gameforge": {\n "antiCheat": {\n "enabled": true,\n "serverAuthoritative": true\n },\n "rules": [\n {\n "type": "speed-check",\n "maxSpeed": 100\n },\n {\n "type": "position-validation",\n "enabled": true\n }\n ]\n }\n}' },
],
},
{
id: 'readme',
name: 'README.md',
type: 'file',
path: '/README.md',
content: '# AeThex Studio Project\n\nThis is a cross-platform game project built with AeThex Studio.\n\n## Platforms\n\n- **Roblox**: Multiplayer game experience\n- **Web**: Browser-based version\n- **Mobile**: iOS & Android apps\n- **Desktop**: Native Windows/Mac/Linux\n\n## Features\n\n- Nexus Engine for real-time state synchronization\n- Passport authentication for unified identity\n- GameForge anti-cheat protection\n\n## Getting Started\n\n1. Select a file from the explorer\n2. Edit your code\n3. Click "Run All Platforms" to test\n4. Deploy when ready!\n',
},
],
openFiles: [],
activeFileId: null,
isSaving: false,
setFiles: (files) => set({ files }),
openFile: (file) => {
const { openFiles } = get();
if (openFiles.find(f => f.id === file.id)) {
set({ activeFileId: file.id });
return;
}
const language = file.name.endsWith('.lua') ? 'lua'
: file.name.endsWith('.ts') || file.name.endsWith('.tsx') ? 'typescript'
: file.name.endsWith('.js') || file.name.endsWith('.jsx') ? 'javascript'
: file.name.endsWith('.html') ? 'html'
: file.name.endsWith('.css') ? 'css'
: file.name.endsWith('.json') ? 'json'
: file.name.endsWith('.md') ? 'markdown'
: 'plaintext';
const newFile: OpenFile = {
id: file.id,
name: file.name,
path: file.path,
content: file.content || '',
language,
isDirty: false,
};
set({
openFiles: [...openFiles, newFile],
activeFileId: file.id,
});
},
closeFile: (fileId) => {
const { openFiles, activeFileId } = get();
const newOpenFiles = openFiles.filter(f => f.id !== fileId);
const newActiveId = activeFileId === fileId
? (newOpenFiles.length > 0 ? newOpenFiles[newOpenFiles.length - 1].id : null)
: activeFileId;
set({
openFiles: newOpenFiles,
activeFileId: newActiveId,
});
},
setActiveFile: (fileId) => set({ activeFileId: fileId }),
updateFileContent: (fileId, content) => {
const { openFiles } = get();
set({
openFiles: openFiles.map(f =>
f.id === fileId ? { ...f, content, isDirty: true } : f
),
});
},
saveFile: (fileId) => {
const { openFiles } = get();
set({ isSaving: true });
// Simulate save
setTimeout(() => {
set({
openFiles: openFiles.map(f =>
f.id === fileId ? { ...f, isDirty: false } : f
),
isSaving: false,
});
}, 500);
},
saveAllFiles: () => {
set({ isSaving: true });
setTimeout(() => {
set({
openFiles: get().openFiles.map(f => ({ ...f, isDirty: false })),
isSaving: false,
});
}, 500);
},
}));