Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"unreal-mcp": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
}
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,16 @@
"EXPORTMAP",
"fguid",
"gatherable",
"Qfecheck",
"scrollview",
"SERIALSIZES",
"SOFTOBJECTPATH",
"TEMPLATEINDEX",
"uasset",
"uassets",
"UPACKAGE"
"umap",
"UPACKAGE",
"uproject"
],
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
Expand Down
48 changes: 0 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,3 @@ $ yarn install
# Run the app in development mode
$ yarn dev
```

## Dev Notes
### Keeping the UObject enum in sync with UE5 source
The enums at `src/main/lib/uasset/enums.ts` mirror a handful of headers from
[EpicGames/UnrealEngine](https://github.com/EpicGames/UnrealEngine) (private repo, requires an
Epic-linked GitHub account). A full build of the engine is ~400GB and even a plain clone is
10-15GB, so we keep a sparse checkout of just the `UObject` headers we care about.

The source lives at `.ue5/UnrealEngine/` (already in `.gitignore`).

One-time setup, from the repo root:
```bash
$ git clone --filter=blob:none --sparse https://github.com/EpicGames/UnrealEngine.git .ue5/UnrealEngine
$ cd .ue5/UnrealEngine
$ git sparse-checkout set Engine/Source/Runtime/Core/Public/UObject Engine/Source/Runtime/CoreUObject/Public/UObject
```

**Important:** always run `git sparse-checkout` commands from **inside** `.ue5/UnrealEngine/`, or
pass `-C .ue5/UnrealEngine` explicitly. If you run one from the gitgame repo root by accident,
git will silently enable sparse-checkout on the **gitgame** repo (because that's the enclosing
`.git` it finds) and hide 99% of your working tree. Recover with:
```bash
$ git sparse-checkout disable
```
Files are never lost, they're still in `HEAD`/index, just filtered from the working tree.

If the working tree stays empty after `set` on the UE clone (blob fetch silently failing on the
private repo), force a re-materialize:
```bash
$ git -C .ue5/UnrealEngine sparse-checkout reapply
$ git -C .ue5/UnrealEngine checkout HEAD -- .
```

To add more UE paths later (e.g. when we start writing type-specific shapers and need
`Engine/Classes/Engine/Texture.h`):
```bash
$ git -C .ue5/UnrealEngine sparse-checkout add Engine/Source/Runtime/Engine/Classes/Engine
```

To pull upstream updates before resyncing enum values:
```bash
$ git -C .ue5/UnrealEngine pull
```

Files that map to `enums.ts`:
- `Engine/Source/Runtime/Core/Public/UObject/ObjectVersion.h`: `EUnrealEngineObjectUE4Version`, `EUnrealEngineObjectUE5Version`
- `Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h`: `PackageFlags`, `EObjectFlags`
- `Engine/Source/Runtime/CoreUObject/Public/UObject/PackageFileSummary.h`: header layout the parser reads
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"name": "@cybearl/gitgame",
"version": "0.0.0-semantically-released",
"productName": "gitgame",
"description": "A small tool with a web interface to simplify UE5-based game development with Git LFS.",
"author": "Cybearl <contact@cybearl.com> (https://www.cybearl.com/)",
"license": "MIT",
Expand Down
13 changes: 10 additions & 3 deletions src/main/config/dialogs.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { DialogVariant } from "@/main/types/dialogs"

/**
* The main configuration for dialogs.
*/
const DIALOGS_CONFIG = {
const DIALOGS_CONFIG: {
sizes: Record<DialogVariant, { width: number; height: number }>
} = {
sizes: {
confirm: { width: 420, height: 230 },
error: { width: 480, height: 300 },
confirm: { width: 480, height: 300 },
message: { width: 480, height: 230 },
error: { width: 480, height: 230 },
"error-with-details": { width: 480, height: 380 },
update: { width: 480, height: 380 },
},
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/config/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
const GIT_CONFIG = {
defaultLogOutputLimit: 100,
checkAttributeChunkSize: 256,
maxBufferSize: 64 * 1024 * 1024, // 64 MB
lockConcurrency: 6,
lockTimeoutMs: 60_000,
}

export default GIT_CONFIG
9 changes: 9 additions & 0 deletions src/main/config/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

const UPDATER_CONFIG = {
checkIntervalMs: 4 * 60 * 60 * 1000,
startupCheckDelayMs: 15 * 1000,
releasesUrl: "https://github.com/cybearl/gitgame/releases/latest",
autoInstallPlatforms: ["win32"] as NodeJS.Platform[],
simulatedDownload: {
version: "9.9.9",
totalBytes: 86 * 1024 * 1024,
tickMs: 120,
tickPercent: 4,
},
}

export default UPDATER_CONFIG
13 changes: 10 additions & 3 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { registerGitCommandsHandlers } from "@main/lib/gitCommands/handlers"
import { registerLfsCommandsHandlers } from "@main/lib/lfsCommands/handlers"
import { registerProjectsHandlers } from "@main/lib/projects/handlers"
import { registerShellsHandlers } from "@main/lib/shells/handlers"
import { startAutoUpdater } from "@main/lib/updater"
import { attachWindowStateBroadcaster, registerWindowsControlHandlers } from "@main/lib/windows"
import { startUpdater } from "@main/lib/updater"
import { registerUpdaterHandlers } from "@main/lib/updater/handlers"
import { registerUProjectHandlers } from "@main/lib/uproject/handlers"
import { attachWindowStateBroadcaster, registerWindowsControlHandlers, setMainWindow } from "@main/lib/windows"
import { app, BrowserWindow, shell } from "electron"

/**
Expand All @@ -25,6 +27,9 @@ function createMainWindow(): BrowserWindow {
// Broadcast focus/visibility/maximize/fullscreen state changes to the renderer
attachWindowStateBroadcaster(window)

// Track it as the main window, so app-global features can parent to it
setMainWindow(window)

// Open external links in the user's default browser
window.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url)
Expand All @@ -50,9 +55,11 @@ app.whenReady().then(() => {
registerLfsCommandsHandlers()
registerFileTreeHandlers()
registerProjectsHandlers()
registerUProjectHandlers()
registerShellsHandlers()
registerUpdaterHandlers()
createMainWindow()
startAutoUpdater()
startUpdater()

// Re-create a window in the app when the dock icon is clicked (macOS)
app.on("activate", () => {
Expand Down
82 changes: 54 additions & 28 deletions src/main/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* The constants used throughout the application.
* The constants for the main process.
*/
const CONSTANTS = {
titleBarHeight: 28,
Expand Down Expand Up @@ -39,46 +39,72 @@ const CONSTANTS = {
projectsClearRecent: "projects:clear-recent",
projectsGetPreferences: "projects:get-preferences",
projectsSetPreferences: "projects:set-preferences",
// UProject
uprojectOpen: "uproject:open",
// Shells
shellsOpenExternal: "shells:open-external",
shellsShowFolder: "shells:show-folder",
shellsOpenTerminal: "shells:open-terminal",
// Dialogs
dialogsConfirm: "dialogs:confirm",
dialogsMessage: "dialogs:message",
dialogsError: "dialogs:error",
dialogsErrorWithDetails: "dialogs:error-with-details",
dialogsGetOptions: "dialogs:get-options",
dialogsRespond: "dialogs:respond",
// Updater
updaterGetState: "updater:get-state",
updaterStateChanged: "updater:state-changed",
updaterCheck: "updater:check",
updaterDownload: "updater:download",
updaterInstall: "updater:install",
updaterOpenDialog: "updater:open-dialog",
updaterSimulate: "updater:simulate",
},
updater: {
devCheckMessage:
'Update checks are disabled in development builds, use the "Dev Tools" menu to preview the update dialog.',
},
uproject: {
missingDirectoryMessage: "The project folder no longer exists on disk.",
missingFileMessage: "No .uproject file was found at the root of the project folder.",
openFailureMessage:
"The system could not open the .uproject file, make sure Unreal Engine is installed and registered as the handler for .uproject files.",
},
shells: {
missingFolderMessage: "The folder no longer exists on disk.",
openFolderFailureMessage: "The system could not open the folder in the file manager.",
noTerminalMessage: "No terminal could be launched, none of the ones we know about are installed or on PATH.",

/**
* The terminals tried in order when opening a folder in a terminal, the first one that
* launches wins.
*
* Note: Linux has no standard terminal, hence the list, `x-terminal-emulator` comes
* first because it is the Debian alternatives symlink pointing at the user's choice.
*/
terminals: {
win32: [
{ command: "wt.exe", args: ["-d"], appendDir: true },
{ command: "cmd.exe", args: ["/c", "start", "", "cmd.exe"], appendDir: false },
],
darwin: [{ command: "open", args: ["-a", "Terminal"], appendDir: true }],
linux: [
{ command: "x-terminal-emulator", args: [], appendDir: false },
{ command: "gnome-terminal", args: [], appendDir: false },
{ command: "konsole", args: [], appendDir: false },
{ command: "xfce4-terminal", args: [], appendDir: false },
{ command: "alacritty", args: [], appendDir: false },
{ command: "kitty", args: [], appendDir: false },
{ command: "xterm", args: [], appendDir: false },
],
} as Record<string, { command: string; args: string[]; appendDir: boolean }[]>,
},
git: {
logFieldSeparator: "\x1f",
logRecordSeparator: "\x1e",
logFormat: ["%H", "%h", "%s", "%an", "%ae", "%aI"], // Joined with field separator and ends with record separator
},
uasset: {
// Highest "LegacyFileVersion" the summary reader handles, anything below (i.e. more
// negative) uses a summary layout we haven't verified against UE source
currentLegacyFileVersion: -9,
// Prefix that marks user-created (game content) asset packages, imports whose outer
// chain terminates outside this prefix are engine/plugin classes
gamePackagePrefix: "/Game/",
// Bit values of "EPropertyTagFlags", the uint8 bitmask on every property tag header
propertyTagFlag: {
hasArrayIndex: 0x01,
hasPropertyGuid: 0x02,
hasPropertyExtensions: 0x04,
hasBinaryOrNativeSerialize: 0x08,
boolTrue: 0x10,
skippedSerialize: 0x20,
},
// Bit values of "EPropertyTagExtension", the uint8 bitmask written when "hasPropertyExtensions" is set
propertyTagExtension: {
overridableInformation: 0x02,
hasExternalsObjects: 0x04,
},
// Blueprint-specific magic strings the shaper matches on
blueprint: {
componentSuffix: "_GEN_VARIABLE",
compiledClassSuffix: "_C",
},
},
} as const

export default CONSTANTS
Loading
Loading