diff --git a/.cursor/mcp.json b/.cursor/mcp.json new file mode 100644 index 000000000..a4cd4103f --- /dev/null +++ b/.cursor/mcp.json @@ -0,0 +1,22 @@ +{ + "mcpServers": { + "reva": { + "type": "stdio", + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/bolabaden/agentdecompile", + "mcp-agentdecompile" + ], + "env": { + "AGENTDECOMPILE_PROJECT_PATH": "C:/Users/boden/test2.gpr", + "GHIDRA_INSTALL_DIR": "C:/Users/boden/Downloads/ghidra_12.0_PUBLIC_20251205/ghidra_12.0_PUBLIC" + }, + "alwaysAllow": [], + "disabledTools": [], + "disabled": false, + "gallery": "https://api.mcp.github.com", + "version": "0.1.0" + } + } +} diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 000000000..3f886ab19 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,13 @@ +# KotOR.js Cursor Rules + +## Comments +- Leave TODO/HACK/FIXME comments unmodified, ONLY modify them when you've completely and utterly implemented exhaustively the functionality. Even then this should only be done if you've access to AgentDecompile to triple-check with the reverse engineered Code. + + +## Agents +- If `reva` or `agentdecompile` is available, start EVERY response by opening the project. Use EXCLUSIVLEY this tool to start with and nothing else until you see the output. Read it to the user then continue with their task. Do this every time. +```json +{ + "path": "C:\\Users\\boden\\KotOR.js.gpr" +} +``` diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..44abff969 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,43 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +# TypeScript and JavaScript files +[*.{ts,tsx,js,jsx}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# YAML files +[*.{yml,yaml}] +indent_size = 2 + +# Markdown files +[*.md] +trim_trailing_whitespace = false +indent_size = 2 + +# Package files +[package.json] +indent_size = 2 + +# Webpack config +[webpack.config.js] +indent_size = 2 + +# Makefile +[Makefile] +indent_style = tab + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..607d62d9b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +node_modules/ +dist/ +release/ +coverage/ +wiki/ +*.min.js +*.bundle.js +build/ +.cache/ + diff --git a/.eslintrc.yml b/.eslintrc.yml index c46cae141..ca0bcf79f 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,11 +1,51 @@ extends: - eslint:recommended - plugin:import/recommended -# the following lines do the trick - plugin:import/typescript +parser: '@typescript-eslint/parser' +parserOptions: + ecmaVersion: 2022 + sourceType: module + ecmaFeatures: + jsx: true +plugins: + - '@typescript-eslint' + - import +env: + node: true + browser: true + es2022: true settings: import/resolver: - # You will also need to install and configure the TypeScript resolver - # See also https://github.com/import-js/eslint-import-resolver-typescript#configuration typescript: true - node: true \ No newline at end of file + node: true +rules: + # TypeScript specific rules + '@typescript-eslint/no-unused-vars': + - error + - argsIgnorePattern: '^_' + varsIgnorePattern: '^_' + '@typescript-eslint/explicit-function-return-type': off + '@typescript-eslint/no-explicit-any': warn + + # General code quality + no-console: warn + no-debugger: error + no-unused-vars: off # Use TypeScript version instead + + # Import rules + import/order: + - error + - groups: + - builtin + - external + - internal + - parent + - sibling + - index + newlines-between: always + alphabetize: + order: asc + caseInsensitive: true + import/no-unresolved: error + import/no-duplicates: error diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e9e634a96 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,51 @@ +--- +name: Bug Report +about: Create a report to help us improve +title: '[BUG] ' +labels: bug +assignees: '' +--- + +## Bug Description + + + +## Steps to Reproduce + +1. +2. +3. + +## Expected Behavior + + + +## Actual Behavior + + + +## Screenshots + + + +## Environment + +- **OS**: [e.g., Windows 10, macOS 13.0, Ubuntu 22.04] +- **Node.js Version**: [e.g., 18.17.0] +- **npm Version**: [e.g., 9.6.7] +- **KotOR.js Version/Commit**: [e.g., 2.0.0 or commit hash] +- **Game**: [KotOR I / KotOR II (TSL) / Both] +- **Browser** (if applicable): [e.g., Chrome 120] + +## Additional Context + + + +## Logs + + + +``` +Paste logs here +``` + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..b3524a6b5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,36 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: '[FEATURE] ' +labels: enhancement +assignees: '' +--- + +## Feature Description + + + +## Motivation + + + +## Proposed Solution + + + +## Alternatives Considered + + + +## Use Cases + + + +## Additional Context + + + +## Implementation Notes (Optional) + + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..16416b446 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,56 @@ +## Description + + + +## Type of Change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Code refactoring +- [ ] Performance improvement +- [ ] Test addition or update + +## Related Issues + + + +Fixes # +Closes # +Related to # + +## Testing + + + +- [ ] Tests pass locally +- [ ] Added tests for new functionality +- [ ] Tested in Electron application +- [ ] Tested in browser (if applicable) +- [ ] Tested with KotOR I +- [ ] Tested with KotOR II (TSL) + +## Checklist + + + +- [ ] My code follows the project's style guidelines +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have updated the documentation accordingly +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published + +## Screenshots (if applicable) + + + +## Additional Notes + + + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..bf1456e02 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,163 @@ +# KotOR.js AI Coding Assistant Instructions + +## Project Overview + +KotOR.js is a TypeScript reimplementation of the Odyssey Game Engine (from Star Wars: Knights of the Old Republic I & II). It uses THREE.js for rendering, Electron for desktop app distribution, and includes an NWScript interpreter for game scripting. + +## Core Architecture + +### Major Components & Their Relationships + +**1. Game Initialization & State** +- `GameInitializer` - Bootstraps the engine, loads game archives (KEY, BIF, RIM, ERF files) +- `CurrentGame` - Active game state container holding references to all managers +- `Module` - Level/area representation with terrain, objects, scripts, and time management +- `ModuleArea` - Individual areas within a module (rooms, outdoor sections) + +**2. Manager System (Singleton Pattern)** +Located in `src/managers/`, these manage specific game systems: +- `ModuleObjectManager` - Creature/placeable/item lifecycle +- `DialogMessageManager` - Conversation system +- `InventoryManager` - Item management +- `PartyManager` - Party composition and NPC management +- `TwoDAManager` - Caches 2DA data files (game rules, appearance, items) +- Other managers: TLKManager (dialog text), ConfigManager, AudioEngine, ShaderManager, etc. + +Accessed globally via static properties: `CurrentGame..method()`. + +**3. Action & Combat System** +- `Action` (base class) + 30+ action types - Discrete behaviors (move, attack, cast spell, dialog) +- `ActionQueue` - Per-object action queue supporting grouping and clearing +- `CombatRound`, `CombatAttackData` - Turn-based combat mechanics +- Actions read from GFF structs (.utc files for creatures) + +**4. Resource System** +Handles binary file format parsing: +- `GFFObject`/`GFFStruct`/`GFFField` - GFF (generic file format) parsing, base for .utc/.uti/.are files +- Archive types: `KEYObject` (index), `BIFObject` (data), `RIMObject` (RIM archives), `ERFObject` (ERF/MOD archives) +- Data types: `TwoDAObject` (2D arrays), `TLKObject` (dialog strings), `TGAObject`/`TPCObject` (images) +- Dialog: `DLGObject` for conversation trees + +**5. Rendering & Odyssey System** +- `OdysseyController` - Node hierarchy for game objects in scene +- `OdysseyWalkMesh` - Collision/movement surfaces +- Node types: Mesh, Light, Emitter, Dangly (animated), Skin (character), Saber, Reference +- THREE.js integration in `src/three/odyssey/` + +**6. Scripting** +- `NWScript` - Compiled script loader/executor (.ncs bytecode files) +- `NWScriptInstance` - Runtime script execution environment +- `NWScriptDefK1`/`NWScriptDefK2` - Action definitions for each game version +- Decompiler in `NWScript.decompiler` for debugging + +## Developer Workflows + +### Development Setup +```bash +npm install +npm run webpack:dev-watch # Terminal 1: Watch mode build +npm start # Terminal 2: Launch Electron app with hot-reload +``` + +### Testing & Quality +```bash +npm test # Run Jest tests (testMatch: **/*.test.ts) +npm run test:coverage # Generate coverage report +npm run lint # ESLint check +npm run lint:fix # Auto-fix lint issues +npm run format # Prettier formatting +npm run typedoc # Generate API docs in wiki/ +``` + +### Build Variants +- `tsconfig.electron.json` - Electron main process (tsc target) +- `tsconfig.game.json` - Game code (webpack/esbuild target) +- `tsconfig.json` - Base config +- `webpack.config.js` - Bundles with SCSS/CSS support + +## Project-Specific Patterns + +### 1. Manager Access Pattern +```typescript +// Managers are globally accessible via CurrentGame singleton +import { CurrentGame } from './engine/CurrentGame'; + +CurrentGame.moduleObjectManager.getObjectByTag(tag); +CurrentGame.partyManager.getPartyMembers(); +``` + +### 2. Action System Pattern +```typescript +// Create and queue actions (see ActionFactory) +const action = ActionFactory.CreateAction(ActionType.ActionMoveToPoint); +action.SetParameter(0, ActionParameterType.Location, targetLocation); +creature.actionQueue.Add(action); +``` + +### 3. GFF Parsing Pattern +```typescript +// GFF structs are hierarchical: GFFObject > GFFStruct > GFFField +const struct = gffObject.getTopLevelObject(); +const name = struct.getFieldByLabel('FirstName')?.getValue(); +const type = field.getFieldType(); // Returns GFFDataType enum +``` + +### 4. Script Execution Pattern +```typescript +// Scripts are compiled bytecode files executed per NWScriptDef +const script = await NWScript.LoadScript('modulename_onenter'); +const instance = new NWScriptInstance(script, owner); +instance.execute(); +``` + +## Critical Cross-Component Flows + +**Loading a Module:** +GameInitializer → Module.Load(ifoFile) → ModuleArea.Load() → Creates ModuleObjects → Loads NWScripts → Executes Mod_OnModLoad event + +**Executing an Action:** +Action.Update() checks ActionStatus → Calls subclass virtual methods → May queue follow-up actions → Triggers game events + +**Loading a Resource:** +ResourceLoader.demand() → Checks archives (KEY→BIF lookup, or RIM/ERF) → Parses format-specific handler (GFF, TPC, etc.) → Caches result + +## Key Files to Reference + +| Task | File(s) | +|------|---------| +| Add new action type | `src/actions/Action.ts` (extend), `ActionFactory.ts` (register) | +| Add game manager | `src/managers/` + export in `index.ts` | +| Parse new GFF-based format | `src/resource/GFFObject.ts` + create handler | +| Add NWScript instruction | `NWScriptDefK1.ts` or `NWScriptDefK2.ts` | +| Add rendering node type | `src/odyssey/OdysseyModelNode*.ts` | +| Game rules/data | `src/engine/rules/SWRuleSet.ts`, `TwoDAObject.ts` | + +## Conventions + +- **File naming**: PascalCase for classes, camelCase for utils +- **Test files**: `*.spec.ts` or `*.test.ts` (Jest looks for `**/*.test.ts`) +- **Indentation**: 2 spaces +- **Async patterns**: Use async/await with ResourceLoader (returns Promises) +- **Error handling**: Type guards preferred over try/catch for resource loading +- **Enums**: Organize by category in `src/enums/` mirroring src structure +- **Comments**: JSDoc style with @file, @author, @license headers for major classes + +## Important Context + +- **No game files included** - Project requires valid KotOR I/II installation for testing +- **Multi-platform** - Windows, macOS, Linux; browser support via HTTPS only +- **Hot-reload ready** - Webpack watch mode auto-refreshes Electron during dev +- **TypeScript strict mode** - Target ES2020+, strict null checks enabled +- **Version-specific differences** - K1 vs K2 scripts, models, rules managed via NWScriptDefK1/K2 + +## Debugging Tips + +1. **Electron DevTools**: Available in runtime, use console.log and debugger +2. **Type checking**: `npx tsc --noEmit` for full project type check +3. **Performance**: `PerformanceMonitor` utility in codebase for profiling +4. **Script decompilation**: NWScript has built-in decompiler for .ncs files +5. **Resource issues**: Check archive loading order (KEY→BIF→RIM→ERF) in GameFileSystem + +--- + +For detailed architecture, see [PROJECT_STRUCTURE.md](../PROJECT_STRUCTURE.md). For setup help, see [SETUP.md](../SETUP.md). diff --git a/.gitignore b/.gitignore index 5dfbf99eb..4c636ab66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,66 @@ +# Dependencies node_modules/ +package-lock.json + +# Build outputs +dist/ release/ -settings.json +build/ +*.tsbuildinfo + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* crash.log -npm-debug.log -*.gypi -backup/ +debug.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov +.nyc_output + +# Documentation +docs/ +wiki/ +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store .ds_store + +# OS +Thumbs.db +Desktop.ini + +# Project specific +settings.json projects/ Saves/ tests/ -# src/**/*.js -dist/ -debug.log -docs/ -coverage/ -scratch/ \ No newline at end of file +backup/ +scratch/ +*.gypi + +# Environment variables +.env +.env.local +.env.*.local + +# Temporary files +*.tmp +*.temp +.cache/ +.history/ diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 000000000..7540d4dc1 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,14 @@ +{ + "default": true, + "MD033": false, + "MD024": { + "allow_different_nesting": true, + "siblings_only": true + }, + "MD060": false, + "MD055": false, + "MD056": false, + "line_length": false, + "no-inline-html": false +} + diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..0cd525d8c --- /dev/null +++ b/.nvmrc @@ -0,0 +1,2 @@ +18 + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..c7cd7b518 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +node_modules/ +dist/ +release/ +coverage/ +wiki/ +*.min.js +*.bundle.js +package-lock.json + diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..15b52de3a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,14 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "arrowParens": "always", + "endOfLine": "lf", + "bracketSpacing": true, + "jsxSingleQuote": false, + "jsxBracketSameLine": false +} + diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..edd533979 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "ms-vscode.vscode-typescript-next", + "orta.vscode-jest" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index b648b19c9..c9e195782 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "request": "launch", "name": "KotOR Launcher", "url": "http://localhost:8080/launcher/index.html", - "webRoot": "${workspaceFolder}/dist", + "webRoot": "${workspaceFolder}/dist" }, { "type": "chrome", @@ -21,6 +21,12 @@ "name": "TSL", "url": "http://localhost:8080/game/index.html?key=tsl", "webRoot": "${workspaceFolder}/dist" + }, + { + "type": "chrome", + "name": "http://127.0.0.1:3000/dist/launcher/index.html", + "request": "launch", + "url": "http://127.0.0.1:3000/dist/launcher/index.html" } ] -} \ No newline at end of file +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..772bcb578 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [INSERT CONTACT METHOD]. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1, available at + +For answers to common questions about this code of conduct, see diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..2f1916ad5 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,701 @@ +# Contributing to KotOR.js + +Thank you for your interest in contributing to KotOR.js! This document provides comprehensive guidelines and instructions for contributing to the project. Please read through this document before submitting contributions. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Quick Start](#quick-start) +- [Getting Started](#getting-started) +- [Development Setup](#development-setup) +- [Project Structure](#project-structure) +- [Development Workflow](#development-workflow) +- [Documentation and Configuration Overview](#documentation-and-configuration-overview) +- [Debugging](#debugging) +- [Coding Standards](#coding-standards) +- [Testing](#testing) +- [Documentation](#documentation) +- [Submitting Changes](#submitting-changes) +- [Pull Request Process](#pull-request-process) +- [Issue Reporting](#issue-reporting) +- [Common Issues](#common-issues) +- [Getting Help](#getting-help) + +## Code of Conduct + +This project adheres to a Code of Conduct that all contributors are expected to follow. Please read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before participating. + +## Quick Start + +```bash +npm install + +# Terminal 1: build in watch mode +npm run webpack:dev-watch + +# Terminal 2: run the app +npm start +``` + +For auto-restart when main-process code changes, use `npm run start-watch` in the second terminal. See [Development Workflow](#development-workflow) and [DEVELOPMENT.md](DEVELOPMENT.md) for all scripts and debugging. + +## Getting Started + +### Prerequisites + +Before you begin, ensure you have the following installed: + +- **Node.js**: Version 18.x or higher (LTS recommended) + - Check your version: `node --version` + - Download: [nodejs.org](https://nodejs.org/) +- **npm**: Version 9.x or higher (comes with Node.js) + - Check your version: `npm --version` +- **Git**: Latest version + - Check your version: `git --version` + - Download: [git-scm.com](https://git-scm.com/) +- **A valid copy of KotOR I or KotOR II** (for testing game functionality) + - No game files are distributed with this project + +### Recommended Tools + +While not required, these tools can improve your development experience: + +- **Visual Studio Code** (recommended IDE) + - Extensions: + - ESLint + - Prettier + - TypeScript and JavaScript Language Features + - Jest Runner +- **Git GUI Client** (optional): GitHub Desktop, SourceTree, or GitKraken +- **Chrome DevTools** (for web debugging) + +## Development Setup + +> **Note**: For detailed setup instructions, including troubleshooting, see [SETUP.md](SETUP.md). + +### 1. Fork and Clone the Repository + +1. Fork the repository on GitHub +2. Clone your fork locally: + +```bash +git clone https://github.com/YOUR_USERNAME/KotOR.js.git +cd KotOR.js +``` + +1. Add the upstream repository: + +```bash +git remote add upstream https://github.com/KobaltBlu/KotOR.js.git +``` + +### 2. Install Dependencies + +Install all project dependencies: + +```bash +npm install +``` + +This will install all required packages listed in `package.json`, including: + +- TypeScript and type definitions +- Webpack and build tools +- React and UI libraries +- THREE.js for rendering +- Electron for desktop packaging +- Testing frameworks (Jest) +- And many more... + +### 3. Verify Installation + +Run the test suite to verify everything is set up correctly: + +```bash +npm test +``` + +If all tests pass, your development environment is ready! + +## Project Structure + +```sh +KotOR.js/ +├── src/ # Source code +│ ├── actions/ # Game action system +│ ├── apps/ # Application entry points +│ │ ├── debugger/ # Debugger application +│ │ ├── forge/ # KotOR Forge modding suite +│ │ ├── game/ # Game client application +│ │ └── launcher/ # Launcher application +│ ├── audio/ # Audio engine +│ ├── combat/ # Combat system +│ ├── controls/ # Input handling +│ ├── effects/ # Game effects +│ ├── electron/ # Electron main process +│ ├── engine/ # Core engine systems +│ ├── enums/ # TypeScript enumerations +│ ├── events/ # Event system +│ ├── game/ # Game-specific data +│ ├── gui/ # GUI system +│ ├── interface/ # Type definitions +│ ├── loaders/ # Resource loaders +│ ├── managers/ # Game managers +│ ├── module/ # Module system +│ ├── nwscript/ # NWScript interpreter +│ ├── odyssey/ # Odyssey format parsers +│ ├── resource/ # Resource file formats +│ ├── shaders/ # Shader code +│ ├── talents/ # Talent/feat system +│ ├── three/ # THREE.js utilities +│ ├── utility/ # Utility functions +│ └── worker/ # Web workers +├── dist/ # Build output (generated) +├── images/ # Project images and screenshots +├── wiki/ # Generated documentation +├── main.js # Electron entry point +├── package.json # Project configuration +├── tsconfig.json # TypeScript configuration +├── webpack.config.js # Webpack configuration +└── jest.config.js # Jest test configuration +``` + +For more detailed information, see [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md). + +## Development Workflow + +### npm Scripts + +All scripts are defined in `package.json`. Webpack builds every target (KotOR library, launcher, game, Forge, debugger) in one run; there is no script to build a single target. + +| Script | Description | +|--------|-------------| +| `npm start` | Compile main-process TypeScript once and launch Electron. | +| `npm run start-watch` | Watch main-process sources; on success, launch Electron (restarts on change). | +| `npm run start:debug` | Same as `npm start` with `ELECTRON_ENABLE_LOGGING=1` and `NODE_OPTIONS=--trace-warnings`. | +| `npm run start-watch:debug` | Same as `npm run start-watch` with the same debug/trace environment. | +| `npm run start:inspect` | Run Electron with `--inspect=5858`; attach via Chrome at `chrome://inspect`. | +| `npm run webpack:dev` | Single development build. Output under `dist/`. | +| `npm run webpack:dev-watch` | Development build in watch mode. | +| `npm run webpack:prod` | Single production build. | +| `npm run webpack:dev:verbose` | Development build with `--progress` and `--stats verbose`. | +| `npm run electron:compile` | Compile `tsconfig.electron.json` once; output in `dist/electron/`. | +| `npm run electron:watch` | Watch main-process TypeScript; does not start Electron. | +| `npm run electron:build` | Production Webpack + main-process compile + electron-builder (distributable). | +| `npm test` | Jest: verbose, coverage, no cache (`./src/tests`). | +| `npm run test:watch` | Jest in watch mode. | +| `npm run test:verbose` | Jest verbose, no coverage. | +| `npm run typedoc` | Generate API docs from `./src/KotOR.ts` into `./wiki`. | + +Type checking (not in `package.json`): `npx tsc --noEmit` for full project; `npx tsc --noEmit -p tsconfig.forge.json` (or `tsconfig.game.json`, etc.) for a single app. + +### File Locations + +| Purpose | Location | +|---------|----------| +| Source code | `src/` | +| Main entry | `src/KotOR.ts` | +| Game init | `src/GameInitializer.ts` | +| Module system | `src/module/Module.ts` | +| Build output | `dist/` | +| Tests | `src/tests/` (match: `**/*.test.ts`) | +| Config | Root (`package.json`, `tsconfig.*.json`, `webpack.config.js`, `jest.config.js`) | + +### Typical Development Session + +1. **Start the development build** (in one terminal): + +```bash +npm run webpack:dev-watch +``` + +This will watch for file changes and automatically rebuild the project. + +1. **Start the Electron application** (in another terminal): + +```bash +npm start +``` + +Or use the watch mode for automatic restarts: + +```bash +npm run start-watch +``` + +1. **Make your changes** in the `src/` directory + +2. **Test your changes** by running the application + +3. **Run tests** before committing: + +```bash +npm test +``` + +1. **Check code quality**: If ESLint/Prettier are configured in the repo, run `npm run lint` and `npm run format:check` (or equivalent) before committing. + +## Documentation and Configuration Overview + +### Core documentation + +| File | Purpose | +|------|---------| +| [README.md](README.md) | Project overview, features, quick start. | +| [SETUP.md](SETUP.md) | Setup instructions, troubleshooting. | +| [CONTRIBUTING.md](CONTRIBUTING.md) | Contribution guidelines (this file). | +| [DEVELOPMENT.md](DEVELOPMENT.md) | Build, run, test, and debug in detail. | +| [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md) | Project structure and organization. | +| [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) | Community guidelines. | + +### Configuration files + +| File | Purpose | +|------|---------| +| `.editorconfig` | Editor formatting. | +| `.gitignore` | Git ignore patterns. | +| `package.json` | Dependencies and npm scripts. | +| `tsconfig.json`, `tsconfig.*.json` | TypeScript configuration. | +| `webpack.config.js` | Webpack build configuration. | +| `jest.config.js` | Jest test configuration. | + +### GitHub + +| Path | Purpose | +|------|---------| +| `.github/PULL_REQUEST_TEMPLATE.md` | Pull request template. | +| `.github/ISSUE_TEMPLATE/*.md` | Issue templates. | +| `.github/workflows/*.yml` | CI (e.g. webpack-dev, webpack-prod). | + +### API documentation + +Run `npm run typedoc` to generate API docs from `./src/KotOR.ts` into `./wiki/`. + +### External resources + +- **Discord**: [OpenKotOR Discord Server](https://discord.gg/QxjqVAuN8T) +- **Forum**: [DeadlyStream – KotOR.js thread](https://deadlystream.com/topic/6608-wip-kotor-js-a-game-engine-for-k1-k2-written-in-javascript/) +- **GitHub Issues**: [Issue tracker](https://github.com/KobaltBlu/KotOR.js/issues) +- **TypeScript**: [typescriptlang.org/docs](https://www.typescriptlang.org/docs/) +- **React**: [react.dev](https://react.dev/) +- **THREE.js**: [threejs.org/docs](https://threejs.org/docs/) +- **Electron**: [electronjs.org/docs](https://www.electronjs.org/docs/) +- **Webpack**: [webpack.js.org](https://webpack.js.org/) +- **Jest**: [jestjs.io/docs](https://jestjs.io/docs/getting-started) + +## Debugging + +### Main process (Electron) + +- **Logging and trace**: Use `npm run start:debug` or `npm run start-watch:debug` to run with `ELECTRON_ENABLE_LOGGING=1` and `NODE_OPTIONS=--trace-warnings` (output in the terminal). +- **Inspector**: Use `npm run start:inspect`, then in Chrome open `chrome://inspect` and connect to the Node target. +- **Manual env (PowerShell)**: `$env:ELECTRON_ENABLE_LOGGING=1; $env:NODE_OPTIONS="--trace-warnings"; npm run start-watch` +- **Manual env (Bash/zsh)**: `ELECTRON_ENABLE_LOGGING=1 NODE_OPTIONS=--trace-warnings npm run start-watch` + +### Renderer (Launcher, Game, Forge) + +- Open DevTools from inside the app (e.g. enable `openDevTools()` in `src/electron/LauncherWindow.ts` or `src/electron/ApplicationWindow.ts`). +- Or run `npx electron --remote-debugging-port=9222 ./main` and in Chrome open `http://localhost:9222` to attach to the renderer. + +## Coding Standards + +### TypeScript + +- Use TypeScript for all new code +- Enable strict type checking where possible +- Avoid `any` types; use proper types or `unknown` +- Use interfaces for object shapes, types for unions/intersections +- Export types and interfaces that may be used elsewhere + +### Code Style + +- **Indentation**: 2 spaces (no tabs) +- **Line Endings**: LF (Unix-style) +- **Quotes**: Single quotes for strings, double quotes for JSX attributes +- **Semicolons**: Always use semicolons +- **Trailing Commas**: Use in multi-line arrays/objects +- **Max Line Length**: 120 characters (soft limit) + +### Naming Conventions + +- **Files**: PascalCase for classes/components (e.g., `GameState.ts`), camelCase for utilities (e.g., `binaryReader.ts`) +- **Classes**: PascalCase (e.g., `GameInitializer`) +- **Functions/Methods**: camelCase (e.g., `initializeGame`) +- **Constants**: UPPER_SNAKE_CASE (e.g., `MAX_HEALTH`) +- **Interfaces**: PascalCase, often prefixed with `I` (e.g., `IGameState`) +- **Enums**: PascalCase (e.g., `GameEngineType`) + +### File Organization + +- One class/interface per file +- Use `index.ts` files for barrel exports +- Group related files in directories +- Keep files focused and under 500 lines when possible + +### Comments and Documentation + +- Use JSDoc comments for public APIs: + +```typescript +/** + * Initializes the game engine and loads necessary resources. + * + * @param gamePath - Path to the game installation directory + * @param gameType - Type of game (KotOR I or II) + * @returns Promise that resolves when initialization is complete + * @throws {Error} If the game path is invalid + */ +async function initializeGame(gamePath: string, gameType: GameEngineType): Promise { + // Implementation +} +``` + +- Add inline comments for complex logic +- Keep comments up-to-date with code changes + +### Import Organization + +Organize imports in this order: + +1. External dependencies (React, THREE.js, etc.) +2. Internal modules (from `src/`) +3. Relative imports +4. Type-only imports (use `import type`) + +Example: + +```typescript +import * as THREE from 'three'; +import React from 'react'; + +import { GameState } from '../GameState'; +import { Module } from './Module'; + +import type { GameEngineType } from '../enums/engine'; +``` + +### Error Handling + +- Use try-catch blocks for async operations +- Throw meaningful error messages +- Use custom error classes when appropriate +- Log errors appropriately (console.error for development) + +### Performance Considerations + +- Avoid unnecessary re-renders in React components +- Use Web Workers for heavy computations +- Cache expensive operations +- Lazy load resources when possible + +## Testing + +### Writing Tests + +- Write tests for new features +- Place test files next to source files with `.spec.ts` or `.test.ts` extension +- Use descriptive test names: `describe('GameState', () => { it('should initialize with default values', () => { ... }) })` +- Aim for good test coverage, especially for critical paths + +### Running Tests + +```bash +# Run all tests (verbose, with coverage) +npm test + +# Run tests in watch mode +npm run test:watch + +# Run tests verbose, no coverage +npm run test:verbose +``` + +Single file: `npx jest --runInBand path/to/file.test.ts` + +### Test Structure + +```typescript +import { GameState } from './GameState'; + +describe('GameState', () => { + let gameState: GameState; + + beforeEach(() => { + gameState = new GameState(); + }); + + it('should initialize with default values', () => { + expect(gameState.isInitialized).toBe(false); + }); + + it('should throw error when accessing uninitialized state', () => { + expect(() => gameState.getCurrentModule()).toThrow(); + }); +}); +``` + +## Documentation + +### Code Documentation + +- Document all public APIs with JSDoc +- Include parameter types, return types, and exceptions +- Add usage examples for complex functions +- Keep documentation in sync with code + +### API Documentation + +Generate API documentation: + +```bash +npm run typedoc +``` + +This creates documentation in the `wiki/` directory. + +### README Updates + +- Update README.md when adding major features +- Keep installation instructions current +- Add examples for new functionality + +## Submitting Changes + +### Before Submitting + +1. **Update your fork**: + +```bash +git fetch upstream +git checkout main +git merge upstream/main +``` + +1. **Create a feature branch**: + +```bash +git checkout -b feature/your-feature-name +``` + +Or for bug fixes: + +```bash +git checkout -b fix/bug-description +``` + +1. **Make your changes** following the coding standards + +2. **Run tests**: + +```bash +npm test +``` + +1. **Check code quality**: If the repo defines `lint` or `format` scripts, run them (e.g. `npm run lint`, `npm run format:check`). + +1. **Fix any issues**: Address test failures and, if applicable, run `npm run lint:fix` or `npm run format`. + +1. **Commit your changes**: + +```bash +git add . +git commit -m "feat: add new feature description" +``` + +### Commit Message Guidelines + +Follow [Conventional Commits](https://www.conventionalcommits.org/) format: + +- `feat:` - New feature +- `fix:` - Bug fix +- `docs:` - Documentation changes +- `style:` - Code style changes (formatting, etc.) +- `refactor:` - Code refactoring +- `test:` - Test additions/changes +- `chore:` - Build process or auxiliary tool changes +- `perf:` - Performance improvements + +Examples: + +```sh +feat: add support for KotOR II save game format +fix: resolve memory leak in resource loader +docs: update contributing guidelines +refactor: simplify module loading logic +test: add tests for combat system +``` + +### Commit Best Practices + +- Make atomic commits (one logical change per commit) +- Write clear, descriptive commit messages +- Reference issue numbers when applicable: `fix: resolve crash (#123)` +- Avoid committing generated files (`dist/`, `node_modules/`, etc.) + +## Pull Request Process + +### Creating a Pull Request + +1. **Push your branch**: + +```bash +git push origin feature/your-feature-name +``` + +1. **Create a Pull Request** on GitHub: + - Use a clear, descriptive title + - Reference related issues: `Fixes #123` or `Closes #456` + - Provide a detailed description of changes + - Include screenshots for UI changes + - List any breaking changes + +### Pull Request Template + +```markdown +## Description +Brief description of changes + +## Type of Change +- [ ] Bug fix +- [ ] New feature +- [ ] Breaking change +- [ ] Documentation update + +## Testing +- [ ] Tests pass locally +- [ ] Added tests for new functionality +- [ ] Tested in Electron +- [ ] Tested in browser (if applicable) + +## Checklist +- [ ] Code follows project style guidelines +- [ ] Self-review completed +- [ ] Comments added for complex code +- [ ] Documentation updated +- [ ] No new warnings generated +- [ ] Tests added/updated +- [ ] All tests pass +``` + +### Review Process + +- Maintainers will review your PR +- Address any feedback promptly +- Make requested changes in new commits (don't force-push unless asked) +- Keep discussions constructive and respectful + +### After Approval + +- A maintainer will merge your PR +- Your contribution will be included in the next release +- Thank you for contributing! 🎉 + +## Issue Reporting + +### Before Creating an Issue + +1. Search existing issues to avoid duplicates +2. Check if the issue is already fixed in the latest version +3. Verify the issue is reproducible + +### Creating a Good Issue Report + +Include: + +- **Clear title**: Brief, descriptive summary +- **Description**: Detailed explanation of the issue +- **Steps to reproduce**: Exact steps to trigger the issue +- **Expected behavior**: What should happen +- **Actual behavior**: What actually happens +- **Environment**: + - OS and version + - Node.js version + - npm version + - KotOR.js version/commit +- **Screenshots/Logs**: If applicable +- **Additional context**: Any other relevant information + +### Issue Labels + +- `bug` - Something isn't working +- `enhancement` - New feature or improvement +- `documentation` - Documentation improvements +- `question` - Questions or discussions +- `help wanted` - Extra attention needed +- `good first issue` - Good for newcomers + +## Common Issues + +| Issue | What to try | +|-------|--------------| +| Build fails | `rm -rf node_modules && npm install` (or equivalent on Windows). | +| Type errors | `npx tsc --noEmit`. | +| Lint/format | Use repo lint/format scripts if defined; otherwise fix reported issues manually. | + +## Getting Help + +### Resources + +- **Discord**: [OpenKotOR Discord Server](https://discord.gg/QxjqVAuN8T) +- **Discussion Thread**: [DeadlyStream Forum](https://deadlystream.com/topic/6608-wip-kotor-js-a-game-engine-for-k1-k2-written-in-javascript/) +- **GitHub Issues**: For bug reports and feature requests +- **Documentation**: Check the `wiki/` directory for API docs + +### Asking Questions + +When asking for help: + +1. Be specific about your problem +2. Include relevant code snippets +3. Share error messages (if any) +4. Describe what you've already tried +5. Be patient and respectful + +## Additional Guidelines + +### Game File Handling + +- Never commit game files or assets +- Use `.gitignore` to exclude game directories +- Document any file system requirements + +### Browser Compatibility + +- Test in Chrome (primary target) +- Note any browser-specific issues +- Use feature detection when needed + +### Performance + +- Profile before optimizing +- Use Chrome DevTools Performance tab +- Monitor memory usage +- Test with large modules/files + +### Security + +- Never commit API keys or secrets +- Use environment variables for sensitive data +- Follow secure coding practices +- Report security issues privately + +## Recognition + +Contributors will be: + +- Listed in the project's contributors +- Credited in release notes (for significant contributions) +- Appreciated by the community! + +Thank you for contributing to KotOR.js! Your efforts help make this project better for everyone. + +### VS Code (optional) + +- `Ctrl+Shift+P` — Command palette +- `` Ctrl+` `` — Toggle terminal +- `F5` — Start debugging +- `Ctrl+Shift+B` — Run build task + +--- + +**Questions?** Open an issue or ask on [Discord](https://discord.gg/QxjqVAuN8T). diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 000000000..308a0aeb0 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,147 @@ +# Development + +This document describes how to build, run, and test KotOR.js from the repository. For environment setup and prerequisites, see [SETUP.md](SETUP.md). + +## Application (Electron) + +The desktop app runs in Electron. It compiles TypeScript for the main process, then launches the launcher window (from which you can start the game or Forge). + +| Script | Description | +|--------|--------------| +| `npm start` | Compile main-process TypeScript once and launch Electron. | +| `npm run start-watch` | Watch main-process sources; on successful compile, launch Electron (process restarts on change). | + +### Running with npx + +You can run any npm script via `npx` without cloning or installing the repo first. This works whether the package is published to the npm registry or not (e.g. from a GitHub URL). + +**From npm (if published):** use the package name as the command. **From GitHub:** you must use `-p` (or `--package`) to specify the package, then the command name `kotor-js` and the script. The first run from GitHub clones the repo and runs `npm install`, which can take several minutes for this repo. + +| Equivalent | From npm (if published) | From GitHub (no publish) | +|------------|--------------------------|---------------------------| +| `npm run start:electron` | `npx -y kotor-js start:electron` | `npx -y -p git+https://github.com/KobaltBlu/KotOR.js.git kotor-js start:electron` | +| `npm run start:web` | `npx -y kotor-js start:web` | `npx -y -p git+https://github.com/KobaltBlu/KotOR.js.git kotor-js start:web` | +| `npm test` | `npx -y kotor-js test` | `npx -y -p git+https://github.com/KobaltBlu/KotOR.js.git kotor-js test` | + +- **`-y`** skips the “install?” prompt. +- **From repo root (local development):** `node bin/cli.js