-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from ghostboats/dev
Dev
- Loading branch information
Showing
19 changed files
with
442 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,62 @@ | ||
# BG3 Mod Helper Extension | ||
# BG3 Mod Helper - A VSCod(e/ium) Extension | ||
|
||
*Previous versions of this extension required divine.exe. This is no longer needed; instead, the path to LSLib is required.* | ||
Created by ghostboats and khbsd, this VSCod(e/ium) extension is designed to help mod authors speed up their mod creation workflows. The extension includes multiple useful utilities such as: | ||
|
||
This Visual Studio Code extension aids in modding Baldur's Gate 3 by speeding up various tasks. It offers a wide range of functionalities aimed at improving mod development efficiency. | ||
- **Mod Packing/Unpacking** | ||
- **UUID/Handle Generation** | ||
- **UUID Mapping** | ||
- **Handle Management** | ||
- **LSX/XML/LOCA/ETC File Conversions** | ||
- **Generate Mod Templates** | ||
- **Atlas Generation** | ||
- **And More!** | ||
|
||
Please visit the [BG3 Modding Community Wiki](https://wiki.bg3.community/Tools/bg3-mod-helper) for a detailed guide on how to use the extension as both a modder and a developer. | ||
This tool is very functional and follows the philosophy of “Few clicks, few tabs,” enabling modding without frequent tabbing out and minimizing the number of clicks needed. It’s available for both VSCode and VSCodium. | ||
|
||
## Requirements | ||
- **LSLib** | ||
|
||
## General Features | ||
## Getting Started | ||
|
||
- **Generate UUIDs/Handles** via the right-click menu: | ||
- Auto-create a handle in your localization file upon spawning a handle. | ||
- Auto-highlight for quick copy on UUID/Handle generation. | ||
- **Hover over UUIDs/Handles** to find related UUIDs/Handles in your mod's root folder: | ||
- Click the hover to move directly to that file/line. | ||
- **Right-click in the editor** to access tools like the stats/lsx validator and search tool via the export tools menu option (Internet connection required). | ||
- **Right-click in the file tree** to create a BG3 file from the menu (Ctrl+Shift+Q). | ||
- **Convert .DDS or .png files** to the opposite format by right-clicking on them. | ||
- **Resize .DDS/.png files** to a custom size or standard sizes for icons. | ||
- **Enhanced function definitions and parameters** for BG3, including stats functions and progressions. Future updates may include SE functions. | ||
### Install the extension: | ||
|
||
## Data Provider Features | ||
1. Open VSCode. | ||
2. Click on the View tab on the top ribbon. | ||
3. Click on Extensions. | ||
4. In the Search Extensions in Marketplace search box, enter `bg3_mod_helper`. | ||
5. Click Install on the correct extension. | ||
|
||
- **Pack Mod**: Automatically packs your mod and sends the new `.pak` to the Mods folder. | ||
- Auto-creates `meta.lsx` if it's missing and prompts you for details. | ||
- Automatically launches the game if selected in settings. | ||
- Converts all `merged.lsx` to `merged.lsf` for packing. | ||
- Converts all `.xml` localization folders in your Localization (supports multiple languages). | ||
- **Launch Game**: Launch the most recent save on game start. | ||
- **Xml to Loca**: Converts XML files to LOCA files, with options for mass or single file conversion. | ||
- **Generate Folder Structure**: Helps in creating a basic mod folder structure based on user selection. | ||
### Setup Extension Settings: | ||
|
||
## Installation & Download Options | ||
1. Click on “File” in the top ribbon in VSCode. | ||
2. Click on “Preferences” and then “Settings”. | ||
3. Search for `bg3` in the settings search bar. | ||
|
||
To install the BG3 Mod Helper, follow these instructions: | ||
### Adjust paths: | ||
|
||
1. **Open Visual Studio Code**: | ||
- Launch the Visual Studio Code application on your computer. | ||
1. Ensure LSLib.dll is in the folder specified in your settings. | ||
2. Set the Root Mod Path to your workspace folder. | ||
3. Configure other paths such as Mod Destination Path and Game Install Location. | ||
|
||
2. **Access Extensions**: | ||
- Click on `View` in the top menu. | ||
- Select `Extensions` from the dropdown menu. | ||
### Use the Data Provider: | ||
|
||
3. **Install from VSIX**: | ||
- In the Extensions view, click on the `...` button at the top-right corner. | ||
- Choose `Install from VSIX` from the dropdown menu. | ||
Access the data provider from the VSCode sidebar for a quick one-stop shop for the extension’s main functionalities. | ||
|
||
4. **Select the VSIX File**: | ||
- Navigate to the folder where you downloaded the `.vsix` file. | ||
- Select the file and click `Open`. | ||
For detailed setup instructions, features, and usage, please refer to our [wiki page](https://wiki.bg3.community/Tools/bg3-mod-helper). | ||
|
||
### Additional Download Options | ||
- [Nexus Mods](https://www.nexusmods.com/baldursgate3/mods/6574) | ||
- [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=ghostboats.bg3-mod-helper) | ||
- Directly from inside VS Code (search for 'bg3_mod_helper'). | ||
## Requirements | ||
|
||
## Contribution & Feedback | ||
- Visual Studio Code | ||
- LSLib | ||
|
||
This extension was created by **ghostboats** and **khbsd**. For assistance, reach out via: | ||
- [ghostboats on Discord](https://discordapp.com/users/639109932263669781) | ||
- [khbsd on Discord](https://discord.com/users/231090009698992128) | ||
## Limitations | ||
|
||
If you have any feature requests or encounter bugs, please feel free to reach out. Contributions and suggestions are highly appreciated to enhance this tool. | ||
- Unable to work with multiple workspaces in one VSCode window. | ||
- Unable to edit PNGs/DDS files directly in VSCode. | ||
- May encounter bugs when using multiple VSCode windows or having other folders within your workspace. | ||
- Possible lag due to folder/file size. | ||
- No references to base game UUIDs/handles (coming soon). | ||
|
||
A special thanks to the BG3 community, whose documentation provided significant assistance in the development of this extension. | ||
## Support and Community | ||
|
||
Direct messages on Discord are the best way to provide feedback, but other channels like GitHub are also checked. | ||
- For feature requests, bugs, or issues, join our WIP discussion on the [BG3 community Discord](https://discord.gg/bg3community). | ||
- Reach out directly on Discord: | ||
- [ghostboats](https://discordapp.com/users/639109932263669781) | ||
- [khbsd](https://discord.com/users/231090009698992128) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
const vscode = require('vscode'); | ||
const path = require('path'); | ||
const fs = require('fs').promises; | ||
|
||
const { getConfig, getModName } = require('../support_files/config'); | ||
|
||
async function findFiles(dir, fileList = []) { | ||
const files = await fs.readdir(dir, { withFileTypes: true }); | ||
for (const file of files) { | ||
const res = path.resolve(dir, file.name); | ||
if (file.isDirectory()) { | ||
fileList = await findFiles(res, fileList); | ||
} else if (file.name.toLowerCase() === 'modsettings.lsx') { | ||
fileList.push(res); | ||
} | ||
} | ||
return fileList; | ||
} | ||
|
||
async function extractDependencies(filePath) { | ||
const fileContent = await fs.readFile(filePath, 'utf8'); | ||
const profileName = path.basename(path.dirname(filePath)); | ||
const dependencies = []; | ||
const regex = /<node id="ModuleShortDesc">([\s\S]*?)<\/node>/g; | ||
let match; | ||
|
||
while ((match = regex.exec(fileContent))) { | ||
const attributes = {}; | ||
const attributeMatch = /<attribute id="([^"]+)" value="([^"]+)" type="([^"]+)" \/>/g; | ||
let attr; | ||
|
||
while ((attr = attributeMatch.exec(match[1]))) { | ||
attributes[attr[1]] = { | ||
'@id': attr[1], | ||
'@value': attr[2], | ||
'@type': attr[3] | ||
}; | ||
} | ||
|
||
if (Object.keys(attributes).length > 0) { | ||
dependencies.push({ | ||
label: attributes['Name'] ? attributes['Name']['@value'] : 'No Name', | ||
description: filePath, | ||
detail: `Profile Name: ${profileName}`, | ||
attributes: Object.values(attributes) | ||
}); | ||
} | ||
} | ||
|
||
return dependencies; | ||
} | ||
|
||
async function addDependenciesToMeta(metaPath, selectedDependencies) { | ||
let data = await fs.readFile(metaPath, 'utf8'); | ||
let depString = selectedDependencies.map(dep => { | ||
let attrString = dep.attributes.map(attr => `\n\t\t\t\t\t<attribute id="${attr['@id']}" value="${attr['@value']}" type="${attr['@type']}" />`).join(''); | ||
return `\n\t\t\t\t<node id="ModuleShortDesc">${attrString}\n\t\t\t\t</node>`; | ||
}).join(''); | ||
|
||
if (data.includes('<node id="Dependencies"><children>')) { | ||
data = data.replace(/(<node id="Dependencies"><children>)([\s\S]*?)(<\/children><\/node>)/, `$1$2${depString}\n\t\t\t$3`); | ||
} else if (data.includes('<node id="Dependencies" />')) { | ||
data = data.replace('<node id="Dependencies" />', `<node id="Dependencies">\n\t\t<children>${depString}\n\t\t</children>\n\t</node>`); | ||
} else { | ||
data = data.replace('</children>', `\n\t<node id="Dependencies">\n\t\t<children>${depString}\n\t\t</children>\n\t</node>\n</children>`); | ||
} | ||
|
||
await fs.writeFile(metaPath, data, 'utf8'); | ||
} | ||
|
||
const addDependenciesCommand = vscode.commands.registerCommand('bg3-mod-helper.addDependencies', async () => { | ||
const modName = await getModName(); | ||
const rootModPath = getConfig().rootModPath; | ||
const modsDirPath = path.join(rootModPath, "Mods"); | ||
const metaPath = path.join(modsDirPath, modName, "meta.lsx"); | ||
|
||
try { | ||
const playerProfilesPath = path.join(process.env.LOCALAPPDATA, 'Larian Studios', 'Baldur\'s Gate 3', 'PlayerProfiles'); | ||
let allDependencies = []; | ||
const modSettingsFiles = await findFiles(playerProfilesPath); | ||
|
||
for (const filePath of modSettingsFiles) { | ||
const dependencies = await extractDependencies(filePath); | ||
allDependencies.push(...dependencies); | ||
} | ||
|
||
const selected = await vscode.window.showQuickPick(allDependencies, { | ||
canPickMany: true, | ||
placeHolder: 'Select dependencies to add to the meta.lsx' | ||
}); | ||
|
||
if (selected && selected.length > 0) { | ||
await addDependenciesToMeta(metaPath, selected); | ||
vscode.window.showInformationMessage('Dependencies added successfully!'); | ||
} else { | ||
vscode.window.showInformationMessage('No dependencies selected.'); | ||
} | ||
} catch (error) { | ||
console.error(error); | ||
vscode.window.showErrorMessage('Failed to add dependencies: ' + error.message); | ||
} | ||
}); | ||
|
||
module.exports = { addDependenciesCommand }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
const vscode = require('vscode'); | ||
const fs = require('fs'); | ||
const os = require('os'); | ||
|
||
const path = require('path'); | ||
|
||
const LSLIB_DLL = 'LSLib.dll'; | ||
const TOOL_SUBDIR = 'Tools\\'; | ||
|
||
const { getConfig } = require('../support_files/config'); | ||
const { lslibPath, rootModPath } = getConfig(); | ||
const compatRootModPath = path.join(rootModPath + "\\"); | ||
const lslibToolsPath = path.join(lslibPath, TOOL_SUBDIR); | ||
|
||
const { raiseInfo } = require('../support_files/log_utils'); | ||
|
||
|
||
const { LSLIB } = require('../support_files/lslib_utils.js'); | ||
|
||
const debug2 = vscode.commands.registerCommand('bg3-mod-helper.debug2Command', async function () { | ||
raiseInfo("hi dipshit! 💩"); | ||
|
||
}); | ||
|
||
module.exports = { debug2 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const vscode = require('vscode'); | ||
const path = require('path'); | ||
const { getConfig } = require('../support_files/config'); | ||
const fs = require('fs').promises; | ||
|
||
|
||
const openModsFolderCommand = vscode.commands.registerCommand('bg3-mod-helper.openModsFolder', () => { | ||
const { modDestPath } = getConfig(); | ||
vscode.env.openExternal(vscode.Uri.file(modDestPath)); | ||
}); | ||
|
||
const openGameFolderCommand = vscode.commands.registerCommand('bg3-mod-helper.openGameFolder', () => { | ||
const { gameInstallLocation } = getConfig(); | ||
const dataFolderPath = path.join(gameInstallLocation, 'Data'); | ||
vscode.env.openExternal(vscode.Uri.file(dataFolderPath)); | ||
}); | ||
|
||
const openLogsFolderCommand = vscode.commands.registerCommand('bg3-mod-helper.openLogsFolder', async () => { | ||
const { lslibPath } = getConfig(); | ||
async function findLogsFolder(startPath) { | ||
let files = await fs.readdir(startPath, { withFileTypes: true }); | ||
for (let file of files) { | ||
if (file.isDirectory()) { | ||
let fullPath = path.join(startPath, file.name); | ||
if (file.name.toLowerCase() === 'logs') { | ||
return fullPath; | ||
} | ||
let foundFolder = await findLogsFolder(fullPath); | ||
if (foundFolder) return foundFolder; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
const logsFolderPath = await findLogsFolder(lslibPath); | ||
if (logsFolderPath) { | ||
vscode.env.openExternal(vscode.Uri.file(logsFolderPath)); | ||
} else { | ||
vscode.window.showInformationMessage('Logs folder not found in the lslib directory.'); | ||
} | ||
}); | ||
|
||
const openWorkspaceFolderCommand = vscode.commands.registerCommand('bg3-mod-helper.openWorkspaceFolder', () => { | ||
const workspaceFolderPath = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : ''; | ||
if (workspaceFolderPath) { | ||
vscode.env.openExternal(vscode.Uri.file(workspaceFolderPath)); | ||
} else { | ||
vscode.window.showInformationMessage('No workspace folder is open.'); | ||
} | ||
}); | ||
|
||
module.exports = { openModsFolderCommand, openGameFolderCommand, openLogsFolderCommand, openWorkspaceFolderCommand }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.