Merge branch 'main' of https://github.com/OpenStarbound/OpenStarbound
262
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
linux:
|
||||
type: boolean
|
||||
description: Linux
|
||||
default: true
|
||||
windows:
|
||||
type: boolean
|
||||
description: Windows
|
||||
default: false
|
||||
macOS:
|
||||
type: boolean
|
||||
description: macOS
|
||||
default: false
|
||||
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build_windows:
|
||||
name: Build OpenStarbound Windows x64
|
||||
runs-on: windows-latest
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (inputs.windows == true) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-${{ runner.os }}
|
||||
max-size: 1000M
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'windows-release'
|
||||
buildPreset: 'windows-release'
|
||||
testPreset: 'windows-release'
|
||||
|
||||
- name: Run Post-Build Task
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts\ci\windows\post_build.bat
|
||||
|
||||
- name: Assemble Files
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts\ci\windows\assemble.bat
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-All-DevOnly
|
||||
path: dist/*
|
||||
|
||||
- name: Upload Client
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Client
|
||||
path: client_distribution/*
|
||||
|
||||
- name: Upload Server
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Server
|
||||
path: server_distribution/*
|
||||
|
||||
- name: Create Installer
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
& "C:\Program Files (x86)\Inno Setup 6\iscc.exe" /Oinstaller scripts\inno\setup.iss
|
||||
|
||||
- name: Upload Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Installer
|
||||
path: installer/*
|
||||
|
||||
build_linux:
|
||||
name: Build OpenStarbound Linux x86_64
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (inputs.linux == true) }}
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
||||
steps:
|
||||
- name: Install Packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y pkg-config libxmu-dev libxi-dev libgl-dev libglu1-mesa-dev libsdl2-dev
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'linux-release'
|
||||
buildPreset: 'linux-release'
|
||||
|
||||
- name: Prepare Artifacts
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -cvf dist.tar dist
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux
|
||||
path: dist.tar
|
||||
|
||||
- name: Run Tests
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
testPreset: 'linux-release'
|
||||
|
||||
- name: Assemble Files
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts/ci/linux/assemble.sh
|
||||
|
||||
- name: Upload Client Files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux-Client
|
||||
path: client.tar
|
||||
|
||||
- name: Upload Server Files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux-Server
|
||||
path: server.tar
|
||||
|
||||
build-mac-intel:
|
||||
name: Build OpenStarbound macOS x86_64
|
||||
runs-on: macos-13
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (inputs.macOS == true) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.0
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-Intel-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'macos-release'
|
||||
buildPreset: 'macos-release'
|
||||
testPreset: 'macos-release'
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-macOS-Intel
|
||||
path: dist/*
|
||||
|
||||
build-mac-arm:
|
||||
name: Build OpenStarbound macOS arm64
|
||||
runs-on: macos-14
|
||||
if: ${{ (github.event_name != 'workflow_dispatch') || (inputs.macOS == true) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-ARM-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'macos-arm-release'
|
||||
buildPreset: 'macos-arm-release'
|
||||
testPreset: 'macos-arm-release'
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-macOS-Silicon
|
||||
path: dist/*
|
76
.github/workflows/build_linux.yml
vendored
@ -1,76 +0,0 @@
|
||||
name: Ubuntu Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: OpenStarbound Linux x86_64
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Install Packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y pkg-config libxmu-dev libxi-dev libgl-dev libglu1-mesa-dev libsdl2-dev
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'linux-release'
|
||||
buildPreset: 'linux-release'
|
||||
testPreset: 'linux-release'
|
||||
|
||||
- name: Assemble Files
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts/ci/linux/assemble.sh
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux
|
||||
path: dist.tar
|
||||
|
||||
- name: Upload Client Files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux-Client
|
||||
path: client.tar
|
||||
|
||||
- name: Upload Server Files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Linux-Server
|
||||
path: server.tar
|
97
.github/workflows/build_macos.yml
vendored
@ -1,97 +0,0 @@
|
||||
name: macOS
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build-intel:
|
||||
name: OpenStarbound macOS x86_64
|
||||
runs-on: macos-13
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.0
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-Intel-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'macos-release'
|
||||
buildPreset: 'macos-release'
|
||||
testPreset: 'macos-release'
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-macOS-Intel
|
||||
path: dist/*
|
||||
|
||||
build-arm:
|
||||
name: OpenStarbound macOS arm64
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-ARM-${{ runner.os }}
|
||||
max-size: 250M
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'macos-arm-release'
|
||||
buildPreset: 'macos-arm-release'
|
||||
testPreset: 'macos-arm-release'
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-macOS-Silicon
|
||||
path: dist/*
|
89
.github/workflows/build_windows.yml
vendored
@ -1,89 +0,0 @@
|
||||
name: Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build OpenStarbound Windows x64
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install CMake & Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
with:
|
||||
cmakeVersion: 3.29.2
|
||||
|
||||
- name: sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ github.job }}-${{ runner.os }}
|
||||
max-size: 1000M
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: vcpkg
|
||||
uses: lukka/run-vcpkg@v11
|
||||
id: runvcpkg
|
||||
with:
|
||||
vcpkgJsonGlob: '**/source/vcpkg.json'
|
||||
vcpkgConfigurationJsonGlob: '**/source/vcpkg-configuration.json'
|
||||
|
||||
- name: Run CMake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
cmakeListsTxtPath: '${{ github.workspace }}/source/CMakeLists.txt'
|
||||
configurePreset: 'windows-release'
|
||||
buildPreset: 'windows-release'
|
||||
testPreset: 'windows-release'
|
||||
|
||||
- name: Run Post-Build Task
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts\ci\windows\post_build.bat
|
||||
|
||||
- name: Assemble Files
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: scripts\ci\windows\assemble.bat
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-All-DevOnly
|
||||
path: dist/*
|
||||
|
||||
- name: Upload Client
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Client
|
||||
path: client_distribution/*
|
||||
|
||||
- name: Upload Server
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Server
|
||||
path: server_distribution/*
|
||||
|
||||
- name: Create Installer
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: |
|
||||
& "C:\Program Files (x86)\Inno Setup 6\iscc.exe" /Oinstaller scripts\inno\setup.iss
|
||||
|
||||
- name: Upload Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: OpenStarbound-Windows-Installer
|
||||
path: installer/*
|
1
.gitignore
vendored
@ -15,6 +15,7 @@ enc_temp_folder/
|
||||
.cache/
|
||||
/attic/user/
|
||||
/attic/chucklefish/
|
||||
/attic/debug/
|
||||
/tiled/
|
||||
/assets/user/
|
||||
/assets/devel/
|
||||
|
32
README.md
@ -14,22 +14,26 @@ It is still **work-in-progress**.
|
||||
## Installation
|
||||
You can download a nightly build below, or the [latest release](https://github.com/OpenStarbound/OpenStarbound/releases/latest). At the moment, you must copy the game assets (**packed.pak**) from your normal Starbound install to the OpenStarbound assets directory before playing.
|
||||
|
||||
OpenStarbound is a separate installation/executable than Starbound. You can copy your `storage` folder from Starbound to transfer your save data and settings. Launching OpenStarbound with Steam open will load your subscribed Steam mods.
|
||||
|
||||
An installer is available for Windows. otherwise, extract the client/server zip for your platform and copy the game assets (packed.pak) to the OpenStarbound assets folder. the macOS releases currently lack the sbinit.config and folder structure that the Linux & Windows zips have, so you'll need to create those before running them. For macOS releases, it is recommended to build them from source (See guide below).
|
||||
### Nightly Builds
|
||||
These link directly to the latest build from the [Actions](https://github.com/OpenStarbound/OpenStarbound/actions?query=branch%3Amain) tab.
|
||||
|
||||
[**Windows**](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_windows/main):
|
||||
[Installer](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_windows/main/OpenStarbound-Windows-Installer.zip),
|
||||
[Client](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_windows/main/OpenStarbound-Windows-Client.zip),
|
||||
[Server](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_windows/main/OpenStarbound-Windows-Server.zip)
|
||||
**Windows**
|
||||
[Installer](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Windows-Installer.zip),
|
||||
[Client](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Windows-Client.zip),
|
||||
[Server](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Windows-Server.zip)
|
||||
|
||||
[**Linux**](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_linux/main):
|
||||
[Client](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_linux/main/OpenStarbound-Linux-Client.zip),
|
||||
[Server](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_linux/main/OpenStarbound-Linux-Server.zip)
|
||||
**Linux**
|
||||
[Client](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Linux-Client.zip),
|
||||
[Server](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Linux-Server.zip)
|
||||
|
||||
[**macOS**](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_macos/main "overpriced aluminium"):
|
||||
[Intel](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_macos/main/OpenStarbound-Dev-macOS-Intel.zip),
|
||||
[ARM](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build_macos/main/OpenStarbound-Dev-macOS-Silicon.zip)
|
||||
**macOS**
|
||||
[Intel](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Dev-macOS-Intel.zip),
|
||||
[ARM](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main/OpenStarbound-Dev-macOS-Silicon.zip)
|
||||
|
||||
[All Nightly Builds](https://nightly.link/OpenStarbound/OpenStarbound/workflows/build/main)
|
||||
|
||||
## Changes
|
||||
Note: Not every function from [StarExtensions](https://github.com/StarExtensions/StarExtensions) has been ported yet, but near-full compatibility with mods that use StarExtensions features is planned.
|
||||
@ -44,8 +48,16 @@ Note: Not every function from [StarExtensions](https://github.com/StarExtensions
|
||||
* These scripts can modify, read, patch and create new assets!
|
||||
* Lua patch files now exist - **.patch.lua**
|
||||
* These can patch JSON assets, as well as images!
|
||||
### Commands
|
||||
**View OpenStarbound commands with `/help`! You can also view them [here](https://github.com/OpenStarbound/OpenStarbound/blob/main/assets/opensb/help.config.patch)**
|
||||
* Changes to vanilla commands:
|
||||
* `/settileprotection`
|
||||
* You can now specify as many dungeon IDs as you want: `/settileprotection 69 420 false`
|
||||
* You can now specify a range: /settileprotection 0..65535 true
|
||||
### Bug Fixes
|
||||
* Invalid character inventories are updated when loading in, allowing players to swap inventory mods with pre-existing characters.
|
||||
* Fix vanilla world file size bloating issue.
|
||||
* Modifying a single status property no longer re-networks every status property on the entity (server and client must be running at least OpenStarbound 0.15)
|
||||
### Misc
|
||||
* Player functions for saving/loading, modifying the humanoid identity, manipulating the inventory. [Documentation](https://github.com/OpenStarbound/OpenStarbound/blob/main/doc/lua/openstarbound.md)
|
||||
* Character swapping (rewrite from StarExtensions, currently command-only: `/swap name` case-insensitive, only substring required)
|
||||
|
@ -3,7 +3,9 @@
|
||||
"groups": {
|
||||
"camera": { "name": "Camera" },
|
||||
"voice": { "name": "Voice" },
|
||||
"building": { "name": "Building" }
|
||||
"building": { "name": "Building" },
|
||||
"inventory": { "name": "Inventory" },
|
||||
"editing" : { "name" : "Editing" }
|
||||
},
|
||||
"name": "Open^#ebd74a;Starbound",
|
||||
"binds": {
|
||||
@ -15,6 +17,11 @@
|
||||
"group": "camera",
|
||||
"name": "Zoom In"
|
||||
},
|
||||
"takeAll": {
|
||||
"default": [],
|
||||
"group": "inventory",
|
||||
"name": "Take All From Container"
|
||||
},
|
||||
"zoomOut": {
|
||||
"default": [{
|
||||
"type": "key",
|
||||
@ -42,6 +49,18 @@
|
||||
"default": [],
|
||||
"group": "building",
|
||||
"name": "Shrink Building Radius"
|
||||
},
|
||||
"editingCopyItemJson": {
|
||||
"default": [], // [{"type": "key", "value": "C","mods": ["LShift"]}],
|
||||
"name": "Copy Item in Cursor",
|
||||
"group": "editing",
|
||||
"tags" : ["clipboard"]
|
||||
},
|
||||
"editingPasteItemJson": {
|
||||
"default": [], // [{"type": "key", "value": "V", "mods": ["LShift"]}],
|
||||
"name": "Paste Item in Cursor",
|
||||
"group": "editing",
|
||||
"tags" : ["clipboard"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,5 +10,6 @@
|
||||
"scissor" : false,
|
||||
"letterbox" : false
|
||||
},
|
||||
"postProcessLayers": []
|
||||
"postProcessLayers": [],
|
||||
"postProcessGroups": {}
|
||||
}
|
||||
|
7
assets/opensb/font/sources.txt
Normal file
@ -0,0 +1,7 @@
|
||||
m6x11: managore.itch.io/m6x11
|
||||
beech: 04.jp.org
|
||||
twemoji: github.com/jdecked/twemoji
|
||||
unifont: github.com/stgiga/UnifontEX
|
||||
dotsies: dotsies.org
|
||||
newspaper: onlygfx.com/newspaper-cutout
|
||||
pixelhobo: Chucklefish
|
@ -41,6 +41,7 @@
|
||||
|
||||
// Change planet name to support the new internal string formatting.
|
||||
"planetNameFormatString" : "- {} -",
|
||||
"planetTextOffset" : [0, 120],
|
||||
"planetTextStyle" : {
|
||||
"backDirectives" : "border=5;fff;fff?border=1;fff;fff7?multiply=000",
|
||||
"fontSize" : 24
|
||||
|
Before Width: | Height: | Size: 739 B After Width: | Height: | Size: 519 B |
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 117 B |
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 103 B |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 94 B |
Before Width: | Height: | Size: 740 B After Width: | Height: | Size: 338 B |
Before Width: | Height: | Size: 866 B |
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 285 B |
@ -35,7 +35,7 @@ local function finishBind(a, b)
|
||||
if (type(a) == "table") then
|
||||
snareFinished(a)
|
||||
else
|
||||
snareFinished{ type = a, value = b, mods = getMods(value) }
|
||||
snareFinished{ type = a, value = b, mods = getMods(b) }
|
||||
for i, mod in ipairs(mods) do
|
||||
mod.active = false
|
||||
end
|
||||
|
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 152 B |
Before Width: | Height: | Size: 743 B After Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 154 B |
Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 96 B After Width: | Height: | Size: 90 B |
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 335 B |
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 294 B |
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 108 B |
BIN
assets/opensb/interface/opensb/shaders/body.png
Normal file
After Width: | Height: | Size: 323 B |
BIN
assets/opensb/interface/opensb/shaders/categoryname.png
Normal file
After Width: | Height: | Size: 335 B |
BIN
assets/opensb/interface/opensb/shaders/footer.png
Normal file
After Width: | Height: | Size: 138 B |
BIN
assets/opensb/interface/opensb/shaders/group.png
Normal file
After Width: | Height: | Size: 80 B |
BIN
assets/opensb/interface/opensb/shaders/groupback.png
Normal file
After Width: | Height: | Size: 154 B |
BIN
assets/opensb/interface/opensb/shaders/header.png
Normal file
After Width: | Height: | Size: 552 B |
BIN
assets/opensb/interface/opensb/shaders/optionname.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
assets/opensb/interface/opensb/shaders/select.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/opensb/interface/opensb/shaders/selectend.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
150
assets/opensb/interface/opensb/shaders/shaders.config
Normal file
@ -0,0 +1,150 @@
|
||||
{
|
||||
"scripts" : ["/interface/opensb/shaders/shaders.lua"],
|
||||
"scriptDelta" : 0,
|
||||
"scriptWidgetCallbacks" : [
|
||||
"selectGroup",
|
||||
"toggleGroupEnabled",
|
||||
"sliderOptionModified",
|
||||
"textboxOptionModified",
|
||||
"selectOptionPressed"
|
||||
],
|
||||
|
||||
"gui" : {
|
||||
"panefeature" : {
|
||||
"type" : "panefeature",
|
||||
"positionLocked" : false
|
||||
},
|
||||
"background" : {
|
||||
"type" : "background",
|
||||
"fileHeader" : "/interface/opensb/shaders/header.png",
|
||||
"fileBody" : "/interface/opensb/shaders/body.png",
|
||||
"fileFooter" : "/interface/opensb/shaders/footer.png"
|
||||
},
|
||||
"banner" : {
|
||||
"type" : "canvas",
|
||||
"rect" : [146, 187, 398, 215]
|
||||
},
|
||||
"groups" : {
|
||||
"type" : "scrollArea",
|
||||
"rect" : [4, 16, 145, 214],
|
||||
"children" : {
|
||||
"list" : {
|
||||
"type" : "list",
|
||||
"schema" : {
|
||||
"selectedBG" : "/interface/opensb/shaders/groupback.png?multiply=0f0",
|
||||
"unselectedBG" : "/interface/opensb/shaders/groupback.png?multiply=222",
|
||||
"spacing" : [0, 1],
|
||||
"memberSize" : [130, 16],
|
||||
"listTemplate" : {
|
||||
"background" : {
|
||||
"type" : "image",
|
||||
"file" : "/interface/opensb/shaders/groupback.png?multiply=222",
|
||||
"position" : [0, 0],
|
||||
"zlevel" : -1
|
||||
},
|
||||
"button" : {
|
||||
"type" : "button",
|
||||
"callback" : "selectGroup",
|
||||
"caption" : "Unnamed",
|
||||
"base" : "/interface/opensb/shaders/group.png?replace;fff=fff0;000=0007",
|
||||
"hover" : "/interface/opensb/shaders/group.png?replace;fff=fff7;000=3337",
|
||||
"press" : "/interface/opensb/shaders/group.png?replace;fff=000;000=7777",
|
||||
"pressedOffset" : [0, 0],
|
||||
"position" : [0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buttons" : {
|
||||
"horizontal" : {
|
||||
"forward" : { "base" : "", "hover" : "", "pressed" : "" },
|
||||
"backward" : { "base" : "", "hover": "", "pressed" : "" }
|
||||
},
|
||||
"vertical" : {
|
||||
"forward" : {
|
||||
"base" : "/interface/scrollarea/varrow-forward.png?setcolor=fff",
|
||||
"hover" : "/interface/scrollarea/varrow-forwardhover.png",
|
||||
"pressed" : ""
|
||||
},
|
||||
"backward" : {
|
||||
"base" : "/interface/scrollarea/varrow-backward.png?setcolor=fff",
|
||||
"hover" : "/interface/scrollarea/varrow-backwardhover.png",
|
||||
"pressed" : ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"thumbs" : {
|
||||
"horizontal" : {
|
||||
"base" : { "begin" : "", "end" : "", "inner" : "" },
|
||||
"hover" : { "begin" : "", "end" : "", "inner" : "" },
|
||||
"pressed" : { "begin" : "", "end" : "", "inner" : "" }
|
||||
},
|
||||
"vertical" : {
|
||||
"base" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-begin.png",
|
||||
"end" : "/interface/scrollarea/vthumb-end.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-inner.png"
|
||||
},
|
||||
"hover" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-beginhover.png",
|
||||
"end" : "/interface/scrollarea/vthumb-endhover.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-innerhover.png"
|
||||
},
|
||||
"pressed" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-beginhover.png",
|
||||
"end" : "/interface/scrollarea/vthumb-endhover.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-innerhover.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options" : {
|
||||
"type" : "scrollArea",
|
||||
"rect" : [147, 16, 398, 185],
|
||||
"children" : {},
|
||||
"buttons" : {
|
||||
"horizontal" : {
|
||||
"forward" : { "base" : "", "hover" : "", "pressed" : "" },
|
||||
"backward" : { "base" : "", "hover": "", "pressed" : "" }
|
||||
},
|
||||
"vertical" : {
|
||||
"forward" : {
|
||||
"base" : "/interface/scrollarea/varrow-forward.png?setcolor=fff",
|
||||
"hover" : "/interface/scrollarea/varrow-forwardhover.png",
|
||||
"pressed" : ""
|
||||
},
|
||||
"backward" : {
|
||||
"base" : "/interface/scrollarea/varrow-backward.png?setcolor=fff",
|
||||
"hover" : "/interface/scrollarea/varrow-backwardhover.png",
|
||||
"pressed" : ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"thumbs" : {
|
||||
"horizontal" : {
|
||||
"base" : { "begin" : "", "end" : "", "inner" : "" },
|
||||
"hover" : { "begin" : "", "end" : "", "inner" : "" },
|
||||
"pressed" : { "begin" : "", "end" : "", "inner" : "" }
|
||||
},
|
||||
"vertical" : {
|
||||
"base" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-begin.png",
|
||||
"end" : "/interface/scrollarea/vthumb-end.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-inner.png"
|
||||
},
|
||||
"hover" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-beginhover.png",
|
||||
"end" : "/interface/scrollarea/vthumb-endhover.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-innerhover.png"
|
||||
},
|
||||
"pressed" : {
|
||||
"begin" : "/interface/scrollarea/vthumb-beginhover.png",
|
||||
"end" : "/interface/scrollarea/vthumb-endhover.png",
|
||||
"inner" : "/interface/scrollarea/vthumb-innerhover.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
355
assets/opensb/interface/opensb/shaders/shaders.lua
Normal file
@ -0,0 +1,355 @@
|
||||
--constants
|
||||
local PATH = "/interface/opensb/shaders/"
|
||||
local GROUP_LIST_WIDGET = "groups.list"
|
||||
local OPTIONS_WIDGET = "options"
|
||||
|
||||
local fmt = string.format
|
||||
local log = function() end
|
||||
|
||||
function update()
|
||||
end
|
||||
|
||||
|
||||
local function alphabeticalNameSortGreater(a, b) return a.name > b.name end
|
||||
local function alphabeticalNameSortLesser(a, b) return a.name < b.name end
|
||||
local sortedGroups = {}
|
||||
local groups = {}
|
||||
|
||||
local widgetsToGroups = {}
|
||||
local allSettings = {}
|
||||
local shaderConfig
|
||||
|
||||
local function addGroupToList(data)
|
||||
local name = widget.addListItem(GROUP_LIST_WIDGET)
|
||||
widget.setText(fmt("%s.%s.button", GROUP_LIST_WIDGET, name), data.friendlyName)
|
||||
log("Added group ^cyan;%s^reset; to list", data.friendlyName)
|
||||
return name
|
||||
end
|
||||
|
||||
local function parseGroups()
|
||||
for name, data in next, renderer.postProcessGroups() do
|
||||
if not data.hidden then
|
||||
if not data.friendlyName then data.friendlyName = name end
|
||||
data.groupId = name
|
||||
data.name = data.friendlyName
|
||||
groups[data.groupId] = data
|
||||
end
|
||||
end
|
||||
|
||||
for groupId, data in pairs(groups) do
|
||||
sortedGroups[#sortedGroups + 1] = data
|
||||
end
|
||||
table.sort(sortedGroups, alphabeticalNameSortLesser)
|
||||
for i = 1, #sortedGroups do
|
||||
local data = sortedGroups[i]
|
||||
data.index = i
|
||||
local name = addGroupToList(data)
|
||||
data.widget = name
|
||||
widgetsToGroups[name] = data
|
||||
end
|
||||
if sortedGroups[1] then
|
||||
local first = sortedGroups[1].widget
|
||||
widget.setListSelected(GROUP_LIST_WIDGET, first)
|
||||
selectGroup(first)
|
||||
end
|
||||
end
|
||||
|
||||
local activeGroup
|
||||
|
||||
local function addOptionGroup(data, i, added)
|
||||
local y = (i - 1) * -14
|
||||
local bg = {
|
||||
type = "image",
|
||||
file = PATH .. "groupname.png",
|
||||
position = {-12, y}
|
||||
}
|
||||
local name = "group_" .. i
|
||||
widget.addChild(BINDS_WIDGET, bg, name)
|
||||
added[#added + 1] = name
|
||||
local label = {
|
||||
type = "label",
|
||||
value = data.label,
|
||||
wrapWidth = 120,
|
||||
fontSize = 8,
|
||||
hAnchor = "mid",
|
||||
vAnchor = "mid",
|
||||
position = {120, 6}
|
||||
}
|
||||
widget.addChild(fmt("%s.%s", BINDS_WIDGET, name), label, "text")
|
||||
end
|
||||
|
||||
local function digitRegex(n)
|
||||
local i = 0
|
||||
while n ~= math.floor(n) do
|
||||
n = n * 10
|
||||
i = i + 1
|
||||
end
|
||||
return fmt("%%.%df",i) -- create format string %.nf, where n = %d (i with no decimal points)
|
||||
end
|
||||
local optionPrefix = "option_"
|
||||
local optionOffset = #optionPrefix+1
|
||||
local function addOption(data, i, added)
|
||||
local y = (i - 1) * -14
|
||||
local bg = {
|
||||
type = "image",
|
||||
file = PATH .. "optionname.png",
|
||||
position = {-12, y}
|
||||
}
|
||||
local name = "label_" .. data.name
|
||||
widget.addChild(OPTIONS_WIDGET, bg, name)
|
||||
added[#added + 1] = name
|
||||
local label = {
|
||||
type = "label",
|
||||
value = data.label,
|
||||
wrapWidth = 120,
|
||||
fontSize = 8,
|
||||
hAnchor = "mid",
|
||||
vAnchor = "mid",
|
||||
position = {62, 6}
|
||||
}
|
||||
widget.addChild(fmt("%s.%s", OPTIONS_WIDGET, name), label, "text")
|
||||
local value = data.default or 0
|
||||
if not shaderConfig[activeGroup] then
|
||||
shaderConfig[activeGroup] = {parameters={}}
|
||||
end
|
||||
if not shaderConfig[activeGroup].parameters then
|
||||
shaderConfig[activeGroup].parameters = {}
|
||||
end
|
||||
if shaderConfig[activeGroup].parameters[data.name] ~= nil then
|
||||
value = shaderConfig[activeGroup].parameters[data.name]
|
||||
end
|
||||
|
||||
-- todo: finish this
|
||||
if data.type == "slider" then
|
||||
local range = data.range or {0,1}
|
||||
local delta = data.delta or 0.01
|
||||
-- for some reason ranges require ints so
|
||||
local r = {range[1]/delta, range[2]/delta, 1}
|
||||
|
||||
local slider = {
|
||||
type = "slider",
|
||||
callback = "sliderOptionModified",
|
||||
position = {110, y + 2},
|
||||
gridImage = "/interface/optionsmenu/smallselection.png",
|
||||
range = r
|
||||
}
|
||||
name = optionPrefix..data.name
|
||||
added[#added + 1] = name
|
||||
widget.addChild(OPTIONS_WIDGET, slider, name)
|
||||
|
||||
widget.setSliderValue(fmt("%s.%s",OPTIONS_WIDGET,name), value/delta)
|
||||
local valLabel = {
|
||||
type = "label",
|
||||
value = fmt(digitRegex(delta),value),
|
||||
position = {186, y + 2}
|
||||
}
|
||||
added[#added + 1] = name.."_value"
|
||||
widget.addChild(OPTIONS_WIDGET, valLabel, name.."_value")
|
||||
elseif data.type == "select" then
|
||||
local n = #data.values
|
||||
local width = math.floor(118/n)
|
||||
local by = y
|
||||
local buttons = {}
|
||||
for i=0,n-1 do
|
||||
local img = fmt("%sselect.png?crop=0;0;%.0f;13",PATH,width)
|
||||
local button = {
|
||||
type = "button",
|
||||
callback="selectOptionPressed",
|
||||
caption = data.values[i+1],
|
||||
base = img,
|
||||
hover = img.."?brightness=-25",
|
||||
baseImageChecked = img.."?multiply=00ff00",
|
||||
hoverImageChecked = img.."?multiply=00ff00?brightness=-25",
|
||||
position = {110+width*i, by},
|
||||
pressedOffset = {0, 0},
|
||||
checkable = true,
|
||||
checked = (value == i)
|
||||
}
|
||||
name = "select_"..data.name.."_"..i
|
||||
added[#added + 1] = name
|
||||
widget.addChild(OPTIONS_WIDGET, button, name)
|
||||
table.insert(buttons,{widget=fmt("%s.%s",OPTIONS_WIDGET,name),index=i})
|
||||
end
|
||||
for k,v in next, buttons do
|
||||
widget.setData(v.widget,{option=data,index=v.index,buttons=buttons})
|
||||
end
|
||||
--[[local bge = {
|
||||
type = "image",
|
||||
file = PATH.."selectend.png",
|
||||
position = {110+width*3, by}
|
||||
}
|
||||
name = "bgend_"..data.name
|
||||
added[#added + 1] = name
|
||||
widget.addChild(OPTIONS_WIDGET, bge, name)]]
|
||||
end
|
||||
end
|
||||
|
||||
function sliderOptionModified(option, odata)
|
||||
local oname = string.sub(option, optionOffset)
|
||||
local parameter = groups[activeGroup].parameters[oname]
|
||||
local value = widget.getSliderValue(fmt("%s.%s",OPTIONS_WIDGET,option))*parameter.delta
|
||||
|
||||
widget.setText(fmt("%s.%s",OPTIONS_WIDGET,option.."_value"), fmt(digitRegex(parameter.delta),value))
|
||||
|
||||
for k,v in next, parameter.effects do
|
||||
renderer.setEffectParameter(v, oname, value)
|
||||
end
|
||||
shaderConfig[activeGroup].parameters[oname] = value
|
||||
root.setConfiguration("postProcessGroups",shaderConfig)
|
||||
end
|
||||
|
||||
function selectOptionPressed(button,bdata)
|
||||
sb.logInfo(sb.print(bdata))
|
||||
|
||||
for k,v in next, bdata.buttons do
|
||||
if v.index ~= bdata.index then
|
||||
widget.setChecked(v.widget, false)
|
||||
end
|
||||
end
|
||||
|
||||
value = bdata.index
|
||||
|
||||
local oname = bdata.option.name
|
||||
local parameter = groups[activeGroup].parameters[oname]
|
||||
|
||||
for k,v in next, parameter.effects do
|
||||
renderer.setEffectParameter(v, oname, value)
|
||||
end
|
||||
shaderConfig[activeGroup].parameters[oname] = value
|
||||
root.setConfiguration("postProcessGroups",shaderConfig)
|
||||
end
|
||||
|
||||
local function addEnabled(groupname, i, added)
|
||||
local y = (i - 1) * -14
|
||||
local bg = {
|
||||
type = "image",
|
||||
file = PATH .. "optionname.png",
|
||||
position = {-12, y}
|
||||
}
|
||||
local name = "label_" .. i
|
||||
widget.addChild(OPTIONS_WIDGET, bg, name)
|
||||
added[#added + 1] = name
|
||||
local label = {
|
||||
type = "label",
|
||||
value = "Enabled",
|
||||
wrapWidth = 120,
|
||||
fontSize = 8,
|
||||
hAnchor = "mid",
|
||||
vAnchor = "mid",
|
||||
position = {62, 6}
|
||||
}
|
||||
widget.addChild(fmt("%s.%s", OPTIONS_WIDGET, name), label, "text")
|
||||
local checkbox = {
|
||||
type = "button",
|
||||
callback = "toggleGroupEnabled",
|
||||
position = {165, y + 2},
|
||||
pressedOffset = {0, 0},
|
||||
base = "/interface/optionsmenu/checkboxnocheck.png",
|
||||
hover = "/interface/optionsmenu/checkboxnocheckhover.png",
|
||||
baseImageChecked = "/interface/optionsmenu/checkboxcheck.png",
|
||||
hoverImageChecked = "/interface/optionsmenu/checkboxcheckhover.png",
|
||||
checkable = true,
|
||||
checked = renderer.postProcessGroupEnabled(groupname)
|
||||
}
|
||||
name = "check_"..groupname
|
||||
added[#added + 1] = name
|
||||
widget.addChild(OPTIONS_WIDGET, checkbox, name)
|
||||
end
|
||||
|
||||
function toggleGroupEnabled(checkbox, cdata)
|
||||
renderer.setPostProcessGroupEnabled(activeGroup, widget.getChecked(fmt("%s.%s",OPTIONS_WIDGET,checkbox)), true)
|
||||
shaderConfig = root.getConfiguration("postProcessGroups")
|
||||
end
|
||||
|
||||
function selectGroup()
|
||||
local selected = widget.getListSelected(GROUP_LIST_WIDGET)
|
||||
local group = widgetsToGroups[selected]
|
||||
local dataFromPrev = widget.getData(OPTIONS_WIDGET)
|
||||
if dataFromPrev then
|
||||
for i, v in pairs(dataFromPrev) do
|
||||
widget.removeChild(OPTIONS_WIDGET, v)
|
||||
end
|
||||
end
|
||||
widgetsToOptions = {}
|
||||
|
||||
activeGroup = group.groupId
|
||||
|
||||
local bannerOptions = widget.bindCanvas("banner")
|
||||
bannerOptions:clear()
|
||||
|
||||
local bannerName = tostring(group.bannerName or group.name or group.groupId)
|
||||
bannerOptions:drawText(bannerName, {position = {127, 13}, horizontalAnchor = "mid", verticalAnchor = "mid"}, 16)
|
||||
|
||||
local added = {}
|
||||
local index = 0
|
||||
addEnabled(group.groupId,index,added)
|
||||
if group.categories then
|
||||
|
||||
elseif group.parameters then
|
||||
local sortedParams = {}
|
||||
for k,v in next, group.parameters do
|
||||
v.name = k
|
||||
sortedParams[#sortedParams+1] = v
|
||||
end
|
||||
table.sort(sortedParams, alphabeticalNameSortLesser)
|
||||
|
||||
for k,v in next, sortedParams do
|
||||
index = index + 1
|
||||
addOption(v, index, added)
|
||||
end
|
||||
end
|
||||
--[[
|
||||
local categories = group.categories or {}
|
||||
if not categories.unsorted then
|
||||
categories.unsorted = {name = "Unsorted"}
|
||||
end
|
||||
|
||||
local sortedCategories = {}
|
||||
for categoryId, data in pairs(categories) do
|
||||
data.name = tostring(data.name or categoryId)
|
||||
data.sortedOptions = {}
|
||||
sortedCategories[#sortedCategories + 1] = data
|
||||
end
|
||||
|
||||
table.sort(sortedCategories, alphabeticalNameSortLesser)
|
||||
|
||||
for categoryId, data in pairs(categories) do
|
||||
table.sort(data.sortedOptions, alphabeticalNameSortLesser)
|
||||
end
|
||||
|
||||
local onlyUnsorted = not sortedGroups[2] and sortedGroups[1] == categories.unsorted
|
||||
|
||||
for iA = 1, #sortedCategories do
|
||||
local category = sortedCategories[iA]
|
||||
local optionsCount = #category.sortedOptions
|
||||
if optionsCount > 0 then
|
||||
if not onlyUnsorted then
|
||||
index = index + 1
|
||||
addOptionCategory(category, index, added)
|
||||
end
|
||||
for iB = 1, optionsCount do
|
||||
index = index + 1
|
||||
addOption(category.sortedOptions[iB], index, added)
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
widget.setData(OPTIONS_WIDGET, added)
|
||||
end
|
||||
|
||||
|
||||
local function initCallbacks()
|
||||
widget.registerMemberCallback(GROUP_LIST_WIDGET, "selectGroup", selectGroup)
|
||||
end
|
||||
|
||||
function init()
|
||||
shaderConfig = root.getConfiguration("postProcessGroups")
|
||||
--log = chat and chat.addMessage or sb.logInfo
|
||||
|
||||
widget.clearListItems(GROUP_LIST_WIDGET)
|
||||
initCallbacks()
|
||||
parseGroups()
|
||||
|
||||
script.setUpdateDelta(1)
|
||||
end
|
Before Width: | Height: | Size: 163 B After Width: | Height: | Size: 156 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 839 B After Width: | Height: | Size: 676 B |
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 151 B After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 614 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 616 B |
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 388 B |
Before Width: | Height: | Size: 140 B After Width: | Height: | Size: 139 B |
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 140 B |
@ -54,6 +54,24 @@
|
||||
|
||||
"instrumentSlider" : { "type" : "slider", "position" : [62, 158], "gridImage" : "/interface/optionsmenu/largeselection.png" },
|
||||
"instrumentLabel" : { "type" : "label", "position" : [32, 158], "value" : "Tunes" },
|
||||
"instrumentValueLabel" : { "type" : "label", "position" : [192, 158], "hAnchor" : "mid", "value" : "Replace Me" }
|
||||
"instrumentValueLabel" : { "type" : "label", "position" : [192, 158], "hAnchor" : "mid", "value" : "Replace Me" },
|
||||
|
||||
"headRotationLabel" : {
|
||||
"type" : "label",
|
||||
"position" : [25, 51],
|
||||
"hAnchor" : "left",
|
||||
"value" : "HEAD ROTATION"
|
||||
},
|
||||
"headRotationCheckbox" : {
|
||||
"type" : "button",
|
||||
"pressedOffset" : [0, 0],
|
||||
"position" : [104, 51],
|
||||
"base" : "/interface/optionsmenu/checkboxnocheck.png",
|
||||
"hover" : "/interface/optionsmenu/checkboxnocheckhover.png",
|
||||
"baseImageChecked" : "/interface/optionsmenu/checkboxcheck.png",
|
||||
"hoverImageChecked" : "/interface/optionsmenu/checkboxcheckhover.png",
|
||||
"checkable" : true,
|
||||
"checked" : true
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 774 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 153 B After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 153 B After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 75 KiB |
@ -0,0 +1,9 @@
|
||||
{
|
||||
"createCharButton" : {
|
||||
"type" : "button",
|
||||
"base" : "/interface/title/createcharacter.png",
|
||||
"hover" : "/interface/title/createcharacterover.png",
|
||||
"position" : [23, 241],
|
||||
"pressedOffset" : [0, 0]
|
||||
}
|
||||
}
|
@ -6,5 +6,9 @@
|
||||
|
||||
// This is only used if the crafting timer is enabled.
|
||||
// This is how many crafts are ran when the crafting timer wraps.
|
||||
"craftCount" : 1
|
||||
"craftCount" : 1,
|
||||
|
||||
// This is how many of any item can be crafted at once.
|
||||
// This is also used by merchants.
|
||||
"maxSpinCount" : 9999
|
||||
} }
|
@ -13,6 +13,12 @@ local function shift(thing, x, y)
|
||||
return thing
|
||||
end
|
||||
|
||||
local function moveto(thing, otherthing)
|
||||
thing.position[1] = otherthing.position[1]
|
||||
thing.position[2] = otherthing.position[2]
|
||||
return thing
|
||||
end
|
||||
|
||||
-- patch function, called by the game
|
||||
function patch(config)
|
||||
local layout = config.paneLayout
|
||||
@ -42,6 +48,10 @@ function patch(config)
|
||||
shift(clone(layout, "multiTextureLabel", "hardwareCursorLabel"), 98, -11).value = "HARDWARE CURSOR"
|
||||
shift(clone(layout, "multiTextureCheckbox", "hardwareCursorCheckbox"), 99, -11)
|
||||
|
||||
-- Create shader menu button
|
||||
shift(moveto(clone(layout, "accept", "showShadersMenu"), layout.interfaceScaleSlider), 112, -2).caption = "Shaders"
|
||||
|
||||
|
||||
shift(layout.title, 0, 24)
|
||||
shift(layout.resLabel, 0, 28)
|
||||
shift(layout.resSlider, 0, 28)
|
||||
|
12
assets/opensb/interface/windowconfig/merchant.config.patch
Normal file
@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"op" : "test",
|
||||
"path" : "/paneLayout/bgShine/position/1",
|
||||
"value" : -12
|
||||
},
|
||||
{
|
||||
"op" : "replace",
|
||||
"path" : "/paneLayout/bgShine/position/1",
|
||||
"value" : -19
|
||||
}
|
||||
]
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 557 B |
After Width: | Height: | Size: 606 B |
After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 185 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 48 KiB |
@ -12,5 +12,7 @@
|
||||
"maxWireTrans" : 0.4
|
||||
},
|
||||
|
||||
"inventoryFilters" : { "default" : {} },
|
||||
|
||||
"swapDance" : null // Set this to a valid dance to trigger on character swap.
|
||||
}
|
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 168 B |
@ -2,7 +2,7 @@ local module = {}
|
||||
modules.commands = module
|
||||
|
||||
local commands = {}
|
||||
local function command(name, func)
|
||||
local function register(name, func)
|
||||
commands[name] = func
|
||||
end
|
||||
|
||||
@ -12,8 +12,7 @@ function module.init()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
command("run", function(src)
|
||||
register("run", function(src)
|
||||
local success, result = pcall(loadstring, src, "/run")
|
||||
if not success then
|
||||
return "^#f00;compile error: " .. result
|
||||
@ -36,3 +35,5 @@ command("run", function(src)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
module.register = register
|
81
assets/opensb/scripts/opensb/player/copy_paste.lua
Normal file
@ -0,0 +1,81 @@
|
||||
local module = {}
|
||||
modules.copy_paste = module
|
||||
|
||||
local commands = modules.commands
|
||||
local function getItemName(item)
|
||||
return item.parameters.shortdescription
|
||||
or root.itemConfig(item.name).config.shortdescription
|
||||
or item.name
|
||||
end
|
||||
|
||||
local function popupError(prefix, msg)
|
||||
sb.logError("%s: %s", prefix, msg)
|
||||
msg = #msg > 80 and msg:sub(1, 80) .. "..." or msg
|
||||
local findNewLine = msg:find("\n", 1, true)
|
||||
interface.queueMessage("^#f00;error:^reset; " .. (findNewLine and msg:sub(1, findNewLine - 1) or msg), 7)
|
||||
end
|
||||
|
||||
local function getClipboardText()
|
||||
local text = clipboard.hasText() and clipboard.getText()
|
||||
return text and text:sub(1, 1) == "{" and text or nil
|
||||
end
|
||||
|
||||
local function copyItem()
|
||||
local item = player.swapSlotItem() or player.primaryHandItem() or player.altHandItem()
|
||||
if not item then return end
|
||||
|
||||
clipboard.setText(sb.printJson(item, 2))
|
||||
local message = string.format("Copied ^cyan;%s^reset; to clipboard", getItemName(item))
|
||||
interface.queueMessage(message, 4, 0.5)
|
||||
end
|
||||
|
||||
local function pasteItem()
|
||||
if player.swapSlotItem() then return end
|
||||
local data = getClipboardText()
|
||||
if not data then return end
|
||||
|
||||
local success, result = pcall(sb.parseJson, data)
|
||||
if not success then
|
||||
popupError("Error parsing clipboard item", result)
|
||||
else
|
||||
local success, err = pcall(player.setSwapSlotItem, result)
|
||||
if not success then popupError("Error loading clipboard item", err)
|
||||
else
|
||||
local message = string.format("Pasted ^cyan;%s^reset; from clipboard", getItemName(result))
|
||||
interface.queueMessage(message, 4, 0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function module.update()
|
||||
if input.bindDown("opensb", "editingCopyItemJson") then
|
||||
copyItem()
|
||||
end
|
||||
|
||||
if input.bindDown("opensb", "editingPasteItemJson") then
|
||||
pasteItem()
|
||||
end
|
||||
end
|
||||
|
||||
commands.register("exportplayer", function()
|
||||
if not clipboard.available() then
|
||||
return "Clipboard unavailable"
|
||||
end
|
||||
local success, text = pcall(sb.printJson, player.save(), 2)
|
||||
if not success then return text end
|
||||
clipboard.setText(text)
|
||||
return "Exported player to clipboard"
|
||||
end)
|
||||
|
||||
commands.register("importplayer", function()
|
||||
local data = getClipboardText()
|
||||
if not data then return "Clipboard does not contain JSON" end
|
||||
|
||||
local success, result = pcall(sb.parseJson, data)
|
||||
if not success then
|
||||
return "Error parsing player: " .. result
|
||||
else
|
||||
success, result = pcall(player.load, result)
|
||||
return success and "Loaded player from clipboard" or "Error loading player: " .. result
|
||||
end
|
||||
end)
|
@ -1,2 +1,2 @@
|
||||
require "/scripts/opensb/util/modules.lua"
|
||||
modules("/scripts/opensb/player/", {"commands"})
|
||||
modules("/scripts/opensb/player/", {"commands", "copy_paste"})
|
22
assets/opensb/scripts/opensb/universeclient/loadconfig.lua
Normal file
@ -0,0 +1,22 @@
|
||||
-- Meant to manage loading various miscellaneous things from configuration, such as shader parameters.
|
||||
|
||||
local module = {}
|
||||
modules.config_loader = module
|
||||
|
||||
function module.init()
|
||||
local shaderConfig = root.getConfiguration("postProcessGroups") or {}
|
||||
local postProcessGroups = renderer.postProcessGroups()
|
||||
local changes = false
|
||||
for k,v in next, shaderConfig do
|
||||
local group = postProcessGroups[k]
|
||||
if v.parameters then
|
||||
for k2,v2 in next, group.parameters do
|
||||
if v.parameters[k2] ~= nil then
|
||||
for _,e in next, v2.effects do
|
||||
renderer.setEffectParameter(e,k2,v.parameters[k2])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,2 +1,2 @@
|
||||
require "/scripts/opensb/util/modules.lua"
|
||||
modules("/scripts/opensb/universeclient/", {"voicemanager"})
|
||||
modules("/scripts/opensb/universeclient/", {"voicemanager","loadconfig"})
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 145 B |
@ -76,9 +76,13 @@ Returns the asset source path of an asset, or nil if the asset doesn't exist. If
|
||||
Without metadata: Returns an array with all the asset source paths.
|
||||
With metadata: Returns a table, key/value being source path/metadata.
|
||||
|
||||
#### `?` root.assetImage(`String` image)
|
||||
#### `Image` root.assetImage(`String` image)
|
||||
|
||||
*TODO*
|
||||
Returns an image.
|
||||
|
||||
#### `Json` root.assetFrames(`String` imagePath)
|
||||
|
||||
Returns an array containing a `file` (the frames file used for the image) and `frames` (the frame data of the image).
|
||||
|
||||
#### `JsonArray` root.assetPatches(`String` asset)
|
||||
|
||||
@ -112,6 +116,131 @@ Sets a configuration value in `/storage/starbound.config` by path.
|
||||
|
||||
Returns all recipes.
|
||||
|
||||
---
|
||||
# Interface
|
||||
|
||||
The interface table contains bindings which allow scripts to display a message at the bottom of the screen, among other things.
|
||||
|
||||
#### `void` interface.queueMessage(`String` message, [`float` cooldown, [`float` springState]])
|
||||
|
||||
Queues a message popup at the bottom of the screen with an optional **cooldown** and **springState**.
|
||||
|
||||
#### `void` interface.setHudVisible(`bool` visible)
|
||||
|
||||
Sets the HUD's visibility.
|
||||
|
||||
#### `bool` interface.hudVisible()
|
||||
|
||||
Returns the HUD's visibility.
|
||||
|
||||
#### `PaneId` interface.bindRegisteredPane(`string` paneName)
|
||||
Binds a registered pane (defined in `/source/frontend/StarMainInterfaceTypes`) to a Lua value, which can then call widget functions on that pane.
|
||||
<details><summary><b>Panes</b></summary>
|
||||
EscapeDialog<br>
|
||||
Inventory<br>
|
||||
Codex<br>
|
||||
Cockpit<br>
|
||||
Tech<br>
|
||||
Songbook<br>
|
||||
Ai<br>
|
||||
Popup<br>
|
||||
Confirmation<br>
|
||||
JoinRequest<br>
|
||||
Options<br>
|
||||
QuestLog<br>
|
||||
ActionBar<br>
|
||||
TeamBar<br>
|
||||
StatusPane<br>
|
||||
Chat<br>
|
||||
WireInterface<br>
|
||||
PlanetText<br>
|
||||
RadioMessagePopup<br>
|
||||
CraftingPlain<br>
|
||||
QuestTracker<br>
|
||||
MmUpgrade<br>
|
||||
Collections<br>
|
||||
</details>
|
||||
|
||||
#### `void` interface.displayRegisteredPane(`string` paneName)
|
||||
Displays a registered pane.
|
||||
|
||||
|
||||
#### `?` interface.bindCanvas()
|
||||
TODO
|
||||
|
||||
|
||||
#### `int` interface.scale()
|
||||
Returns the scale used for interfaces.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# World
|
||||
|
||||
The world table now contains extra bindings.
|
||||
|
||||
---
|
||||
|
||||
#### `bool` world.isServer()
|
||||
|
||||
Returns whether the script is running on the server or client.
|
||||
|
||||
---
|
||||
|
||||
#### `bool` world.isClient()
|
||||
|
||||
Returns whether the script is running on the server or client.
|
||||
|
||||
---
|
||||
|
||||
The following additional world bindings are available only for scripts running on the client.
|
||||
|
||||
---
|
||||
|
||||
#### `entityId` world.mainPlayer()
|
||||
|
||||
Returns the entity ID of the player hosting the world.
|
||||
|
||||
---
|
||||
|
||||
#### `Vec2F` world.entityAimPosition(`entityId` entityId)
|
||||
|
||||
Returns the current cursor aim position of the specified entity.
|
||||
|
||||
---
|
||||
|
||||
#### `bool` world.inWorld()
|
||||
|
||||
Returns whether any players are in the world.
|
||||
|
||||
---
|
||||
|
||||
The following additional world bindings are available only for scripts running on the server.
|
||||
|
||||
---
|
||||
|
||||
#### `void` world.setExpiryTime(`float` expiryTime)
|
||||
|
||||
Sets the amount of time to persist a ephemeral world when it is inactive.
|
||||
|
||||
---
|
||||
|
||||
#### `string` world.id()
|
||||
|
||||
Returns a `String` representation of the world's id.
|
||||
|
||||
---
|
||||
|
||||
#### `?` world.callScriptContext(`?` ?)
|
||||
|
||||
TODO
|
||||
|
||||
---
|
||||
|
||||
#### `?` world.sendPacket(`?` ?)
|
||||
|
||||
?
|
||||
|
||||
---
|
||||
|
||||
# Player
|
||||
@ -392,9 +521,9 @@ Returns whether the specified item can enter the specified item bag.
|
||||
|
||||
Returns the contents of the specified action bar link slot's specified hand.
|
||||
|
||||
#### `bool` player.setActionBarSlotLink(`String` itemBagName, `ItemDescriptor` item)
|
||||
#### `bool` player.setActionBarSlotLink(`int` slot, `String` hand, `ItemSlot` itemSlot)
|
||||
|
||||
Returns whether the specified item can enter the specified item bag.
|
||||
Links the specified slot's hand to the specified itemSlot.
|
||||
|
||||
---
|
||||
|
||||
@ -413,3 +542,64 @@ Sets the player's interact radius. This does not persist upon returning to the m
|
||||
Returns all the recipes the player can craft with their currently held items and currencies.
|
||||
|
||||
---
|
||||
#### `String` player.currentState()
|
||||
|
||||
Returns the player's current movement state.
|
||||
|
||||
<details><summary><b>Player States</b></summary>
|
||||
idle<br>
|
||||
walk<br>
|
||||
run<br>
|
||||
jump<br>
|
||||
fall<br>
|
||||
swim<br>
|
||||
swimIdle<br>
|
||||
lounge<br>
|
||||
crouch<br>
|
||||
teleportIn<br>
|
||||
teleportOut<br>
|
||||
</details>
|
||||
---
|
||||
|
||||
#### `List<Json>` player.teamMembers()
|
||||
|
||||
Returns an array, each entry being a table with `name`, `uuid`, `entity`, `healthPercentage` and `energyPercentage`
|
||||
|
||||
---
|
||||
|
||||
# Renderer
|
||||
|
||||
The new renderer table is accessible from almost every clientside script and allows configuring shaders.
|
||||
|
||||
---
|
||||
|
||||
#### `void` renderer.setPostProcessGroupEnabled(String group, bool enabled, [bool save])
|
||||
|
||||
Enables or disables a post process shader group. If save is true, this change is saved to configuration as well.
|
||||
|
||||
---
|
||||
|
||||
#### `bool` renderer.postProcessGroupEnabled(String group)
|
||||
|
||||
Returns true if the specified post process group is enabled.
|
||||
|
||||
---
|
||||
|
||||
#### `Json` renderer.postProcessGroups()
|
||||
|
||||
Returns every post process group. Identical to grabbing them from client.config with root.assetJson.
|
||||
|
||||
---
|
||||
|
||||
#### `Json` renderer.setEffectParameter(String effectName, String parameterName, RenderEffectParameter value)
|
||||
|
||||
Sets the specified scriptable parameter of the specified shader effect to the provided value.
|
||||
This is accessed from the shader as a uniform and must be defined in the effect's configuration.
|
||||
|
||||
---
|
||||
|
||||
#### `RenderEffectParameter` renderer.getEffectParameter(String effectName, String parameterName)
|
||||
|
||||
Returns the specified scriptable parameter of the specified shader effect.
|
||||
|
||||
---
|
||||
|
@ -51,6 +51,5 @@ cp \
|
||||
scripts/steam_appid.txt \
|
||||
server_distribution/linux/
|
||||
|
||||
tar -cvf dist.tar dist
|
||||
tar -cvf client.tar client_distribution
|
||||
tar -cvf server.tar server_distribution
|
||||
|
@ -80,6 +80,8 @@ if(NOT DEFINED STAR_SYSTEM)
|
||||
set(STAR_SYSTEM "linux")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(STAR_SYSTEM "freebsd")
|
||||
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
|
||||
set(STAR_SYSTEM "netbsd")
|
||||
elseif(UNIX)
|
||||
set(STAR_SYSTEM "unix")
|
||||
else()
|
||||
@ -208,6 +210,8 @@ elseif(STAR_SYSTEM STREQUAL "linux")
|
||||
set_flag(STAR_SYSTEM_LINUX)
|
||||
elseif(STAR_SYSTEM STREQUAL "freebsd")
|
||||
set_flag(STAR_SYSTEM_FREEBSD)
|
||||
elseif(STAR_SYSTEM STREQUAL "netbsd")
|
||||
set_flag(STAR_SYSTEM_NETBSD)
|
||||
endif()
|
||||
|
||||
if(STAR_SYSTEM_FAMILY STREQUAL "windows")
|
||||
@ -281,14 +285,14 @@ if(STAR_COMPILER_GNU)
|
||||
set(CMAKE_C_FLAGS_DEBUG "-g -Og")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHASSERTS "-g -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHASSERTS "-g -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELWITHASSERTS "-g -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHASSERTS "-g -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
|
||||
@ -312,14 +316,14 @@ elseif(STAR_COMPILER_CLANG)
|
||||
set(CMAKE_C_FLAGS_DEBUG "-g")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHASSERTS "-g -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHASSERTS "-g -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELWITHASSERTS "-g -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHASSERTS "-g -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -DNDEBUG -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -Ofast")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -Ofast")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 -ffast-math")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -ffast-math")
|
||||
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
|
||||
@ -445,6 +449,10 @@ elseif(STAR_SYSTEM_FREEBSD)
|
||||
set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lpthread -lrt")
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lpthread -lrt")
|
||||
|
||||
elseif(STAR_SYSTEM_NETBSD)
|
||||
set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lpthread -lrt -lexecinfo")
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lpthread -lrt -lexecinfo")
|
||||
|
||||
endif()
|
||||
|
||||
# Find all required external libraries, based on build settings...
|
||||
|
@ -46,12 +46,14 @@
|
||||
"displayName": "Linux x64",
|
||||
"binaryDir": "${sourceParentDir}/build/linux-release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"VCPKG_TARGET_TRIPLET": "x64-linux-mixed",
|
||||
"CMAKE_INCLUDE_PATH": "${sourceParentDir}/lib/linux/include",
|
||||
"CMAKE_LIBRARY_PATH": "${sourceParentDir}/lib/linux",
|
||||
"STAR_ENABLE_STATIC_LIBGCC_LIBSTDCXX": true,
|
||||
"STAR_USE_JEMALLOC": true
|
||||
"STAR_USE_JEMALLOC": false
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
|
@ -315,9 +315,11 @@ public:
|
||||
SDL_GetWindowSize(m_sdlWindow, &width, &height);
|
||||
m_windowSize = Vec2U(width, height);
|
||||
|
||||
#ifdef __APPLE__
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
#endif
|
||||
|
||||
m_sdlGlContext = SDL_GL_CreateContext(m_sdlWindow);
|
||||
if (!m_sdlGlContext)
|
||||
|
@ -120,7 +120,7 @@ public:
|
||||
virtual void set(List<RenderPrimitive>& primitives) = 0;
|
||||
};
|
||||
|
||||
typedef Variant<bool, int, float, Vec2F, Vec3F, Vec4F> RenderEffectParameter;
|
||||
typedef Variant<float, int, Vec2F, Vec3F, Vec4F, bool> RenderEffectParameter;
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
@ -141,6 +141,9 @@ public:
|
||||
// The effect config will specify named parameters and textures which can be
|
||||
// set here.
|
||||
virtual void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) = 0;
|
||||
virtual void setEffectScriptableParameter(String const& effectName, String const& parameterName, RenderEffectParameter const& parameter) = 0;
|
||||
virtual Maybe<RenderEffectParameter> getEffectScriptableParameter(String const& effectName, String const& parameterName) = 0;
|
||||
virtual Maybe<VariantTypeIndex> getEffectScriptableParameterType(String const& effectName, String const& parameterName) = 0;
|
||||
virtual void setEffectTexture(String const& textureName, ImageView const& image) = 0;
|
||||
virtual bool switchEffectConfig(String const& name) = 0;
|
||||
|
||||
|
@ -107,8 +107,10 @@ OpenGlRenderer::OpenGlRenderer() {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
if (GLEW_VERSION_4_3) {
|
||||
//glEnable(GL_DEBUG_OUTPUT);
|
||||
//glDebugMessageCallback(GlMessageCallback, this);
|
||||
}
|
||||
|
||||
m_whiteTexture = createGlTexture(Image::filled({1, 1}, Vec4B(255, 255, 255, 255), PixelFormat::RGBA32),
|
||||
TextureAddressing::Clamp,
|
||||
@ -306,8 +308,25 @@ void OpenGlRenderer::loadEffectConfig(String const& name, Json const& effectConf
|
||||
throw RendererException::format("Unrecognized effect parameter type '{}'", type);
|
||||
}
|
||||
|
||||
if (p.second.getBool("scriptable",false)) {
|
||||
if (Json def = p.second.get("default", {})) {
|
||||
if (type == "bool") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)def.toBool();
|
||||
} else if (type == "int") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)(int)def.toInt();
|
||||
} else if (type == "float") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)def.toFloat();
|
||||
} else if (type == "vec2") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)jsonToVec2F(def);
|
||||
} else if (type == "vec3") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)jsonToVec3F(def);
|
||||
} else if (type == "vec4") {
|
||||
effectParameter.parameterValue = (RenderEffectParameter)jsonToVec4F(def);
|
||||
}
|
||||
}
|
||||
effect.scriptables[p.first] = effectParameter;
|
||||
} else {
|
||||
effect.parameters[p.first] = effectParameter;
|
||||
|
||||
if (Json def = p.second.get("default", {})) {
|
||||
if (type == "bool") {
|
||||
setEffectParameter(p.first, def.toBool());
|
||||
@ -325,6 +344,7 @@ void OpenGlRenderer::loadEffectConfig(String const& name, Json const& effectConf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign each texture parameter a texture unit starting with MultiTextureCount, the first
|
||||
// few texture units are used by the primary textures being drawn. Currently,
|
||||
@ -382,6 +402,50 @@ void OpenGlRenderer::setEffectParameter(String const& parameterName, RenderEffec
|
||||
ptr->parameterValue = value;
|
||||
}
|
||||
|
||||
void OpenGlRenderer::setEffectScriptableParameter(String const& effectName, String const& parameterName, RenderEffectParameter const& value) {
|
||||
auto find = m_effects.find(effectName);
|
||||
if (find == m_effects.end())
|
||||
return;
|
||||
|
||||
Effect& effect = find->second;
|
||||
|
||||
auto ptr = effect.scriptables.ptr(parameterName);
|
||||
if (!ptr || (ptr->parameterValue && *ptr->parameterValue == value))
|
||||
return;
|
||||
|
||||
if (ptr->parameterType != value.typeIndex())
|
||||
throw RendererException::format("OpenGlRenderer::setEffectScriptableParameter '{}' parameter type mismatch", parameterName);
|
||||
|
||||
ptr->parameterValue = value;
|
||||
}
|
||||
|
||||
Maybe<RenderEffectParameter> OpenGlRenderer::getEffectScriptableParameter(String const& effectName, String const& parameterName) {
|
||||
auto find = m_effects.find(effectName);
|
||||
if (find == m_effects.end())
|
||||
return {};
|
||||
|
||||
Effect& effect = find->second;
|
||||
|
||||
auto ptr = effect.scriptables.ptr(parameterName);
|
||||
if (!ptr)
|
||||
return {};
|
||||
|
||||
return ptr->parameterValue;
|
||||
}
|
||||
Maybe<VariantTypeIndex> OpenGlRenderer::getEffectScriptableParameterType(String const& effectName, String const& parameterName) {
|
||||
auto find = m_effects.find(effectName);
|
||||
if (find == m_effects.end())
|
||||
return {};
|
||||
|
||||
Effect& effect = find->second;
|
||||
|
||||
auto ptr = effect.scriptables.ptr(parameterName);
|
||||
if (!ptr)
|
||||
return {};
|
||||
|
||||
return ptr->parameterType;
|
||||
}
|
||||
|
||||
void OpenGlRenderer::setEffectTexture(String const& textureName, ImageView const& image) {
|
||||
auto ptr = m_currentEffect->textures.ptr(textureName);
|
||||
if (!ptr)
|
||||
@ -1061,6 +1125,26 @@ void OpenGlRenderer::setupGlUniforms(Effect& effect, Vec2U screenSize) {
|
||||
}
|
||||
|
||||
glUniform2f(m_screenSizeUniform, screenSize[0], screenSize[1]);
|
||||
|
||||
for (auto& param : effect.scriptables) {
|
||||
auto ptr = ¶m.second;
|
||||
auto mvalue = ptr->parameterValue;
|
||||
if (mvalue) {
|
||||
RenderEffectParameter value = mvalue.value();
|
||||
if (auto v = value.ptr<bool>())
|
||||
glUniform1i(ptr->parameterUniform, *v);
|
||||
else if (auto v = value.ptr<int>())
|
||||
glUniform1i(ptr->parameterUniform, *v);
|
||||
else if (auto v = value.ptr<float>())
|
||||
glUniform1f(ptr->parameterUniform, *v);
|
||||
else if (auto v = value.ptr<Vec2F>())
|
||||
glUniform2f(ptr->parameterUniform, (*v)[0], (*v)[1]);
|
||||
else if (auto v = value.ptr<Vec3F>())
|
||||
glUniform3f(ptr->parameterUniform, (*v)[0], (*v)[1], (*v)[2]);
|
||||
else if (auto v = value.ptr<Vec4F>())
|
||||
glUniform4f(ptr->parameterUniform, (*v)[0], (*v)[1], (*v)[2], (*v)[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<OpenGlRenderer::GlFrameBuffer> OpenGlRenderer::getGlFrameBuffer(String const& id) {
|
||||
|
@ -25,6 +25,9 @@ public:
|
||||
void loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) override;
|
||||
|
||||
void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
|
||||
void setEffectScriptableParameter(String const& effectName, String const& parameterName, RenderEffectParameter const& parameter) override;
|
||||
Maybe<RenderEffectParameter> getEffectScriptableParameter(String const& effectName, String const& parameterName) override;
|
||||
Maybe<VariantTypeIndex> getEffectScriptableParameterType(String const& effectName, String const& parameterName) override;
|
||||
void setEffectTexture(String const& textureName, ImageView const& image) override;
|
||||
|
||||
void setScissorRect(Maybe<RectI> const& scissorRect) override;
|
||||
@ -191,6 +194,7 @@ private:
|
||||
GLuint program = 0;
|
||||
Json config;
|
||||
StringMap<EffectParameter> parameters;
|
||||
StringMap<EffectParameter> scriptables; // scriptable parameters which can be changed when the effect is not loaded
|
||||
StringMap<EffectTexture> textures;
|
||||
|
||||
StringMap<GLuint> attributes;
|
||||
|
@ -18,7 +18,6 @@ SET (star_base_HEADERS
|
||||
StarMixer.hpp
|
||||
StarPackedAssetSource.hpp
|
||||
StarRootBase.hpp
|
||||
StarVersion.hpp
|
||||
StarVersionOptionParser.hpp
|
||||
StarWorldGeometry.hpp
|
||||
scripting/StarImageLuaBindings.hpp
|
||||
@ -40,8 +39,7 @@ SET (star_base_SOURCES
|
||||
scripting/StarImageLuaBindings.cpp
|
||||
)
|
||||
|
||||
CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp)
|
||||
ADD_LIBRARY (star_base OBJECT ${star_base_SOURCES} ${star_base_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp)
|
||||
ADD_LIBRARY (star_base OBJECT ${star_base_SOURCES} ${star_base_HEADERS})
|
||||
|
||||
IF(STAR_PRECOMPILED_HEADERS)
|
||||
TARGET_PRECOMPILE_HEADERS (star_base REUSE_FROM star_core)
|
||||
|
@ -68,7 +68,7 @@ static void validatePath(AssetPath const& components, bool canContainSubPath, bo
|
||||
throw AssetException::format("Path '{}' cannot contain directives", components);
|
||||
}
|
||||
|
||||
static void validatePath(StringView const& path, bool canContainSubPath, bool canContainDirectives) {
|
||||
static void validatePath(StringView path, bool canContainSubPath, bool canContainDirectives) {
|
||||
std::string_view const& str = path.utf8();
|
||||
|
||||
size_t end = str.find_first_of(":?");
|
||||
@ -102,6 +102,14 @@ Maybe<RectU> FramesSpecification::getRect(String const& frame) const {
|
||||
}
|
||||
}
|
||||
|
||||
Json FramesSpecification::toJson() const {
|
||||
return JsonObject{
|
||||
{"aliases", jsonFromMap(aliases)},
|
||||
{"frames", jsonFromMapV(frames, jsonFromRectU)},
|
||||
{"file", framesFile}
|
||||
};
|
||||
}
|
||||
|
||||
Assets::Assets(Settings settings, StringList assetSources) {
|
||||
const char* AssetsPatchSuffix = ".patch";
|
||||
const char* AssetsPatchListSuffix = ".patchlist";
|
||||
@ -139,6 +147,12 @@ Assets::Assets(Settings settings, StringList assetSources) {
|
||||
return *assetImage;
|
||||
});
|
||||
|
||||
callbacks.registerCallback("frames", [this](String const& path) -> Json {
|
||||
if (auto frames = imageFrames(path))
|
||||
return frames->toJson();
|
||||
return Json();
|
||||
});
|
||||
|
||||
callbacks.registerCallback("scan", [this](Maybe<String> const& a, Maybe<String> const& b) -> StringList {
|
||||
return b ? scan(a.value(), *b) : scan(a.value());
|
||||
});
|
||||
|
@ -27,7 +27,8 @@ struct FramesSpecification {
|
||||
// Get the target sub-rect of a given frame name (which can be an alias).
|
||||
// Returns nothing if the frame name is not found.
|
||||
Maybe<RectU> getRect(String const& frame) const;
|
||||
|
||||
// Converts to Json.
|
||||
Json toJson() const;
|
||||
// The full path to the .frames file from which this was loaded.
|
||||
String framesFile;
|
||||
// Named sub-frames
|
||||
|
@ -12,10 +12,12 @@ INCLUDE_DIRECTORIES (
|
||||
|
||||
SET (star_client_HEADERS
|
||||
StarClientApplication.hpp
|
||||
StarRenderingLuaBindings.hpp
|
||||
)
|
||||
|
||||
SET (star_client_SOURCES
|
||||
StarClientApplication.cpp
|
||||
StarRenderingLuaBindings.cpp
|
||||
)
|
||||
|
||||
IF (STAR_SYSTEM_WINDOWS)
|
||||
@ -29,12 +31,16 @@ ADD_EXECUTABLE (starbound WIN32
|
||||
$<TARGET_OBJECTS:star_application> $<TARGET_OBJECTS:star_rendering> $<TARGET_OBJECTS:star_windowing> $<TARGET_OBJECTS:star_frontend>
|
||||
${star_client_HEADERS} ${star_client_SOURCES} ${star_client_RESOURCES})
|
||||
|
||||
IF(STAR_PRECOMPILED_HEADERS)
|
||||
IF (STAR_PRECOMPILED_HEADERS)
|
||||
TARGET_PRECOMPILE_HEADERS (starbound REUSE_FROM star_core)
|
||||
ENDIF()
|
||||
|
||||
IF(UNIX)
|
||||
set_target_properties (starbound PROPERTIES LINK_FLAGS "-Wl,-rpath,'$ORIGIN'")
|
||||
IF (UNIX)
|
||||
SET_TARGET_PROPERTIES (starbound PROPERTIES LINK_FLAGS "-Wl,-rpath,'$ORIGIN'")
|
||||
ENDIF()
|
||||
|
||||
IF (STAR_SYSTEM_MACOS)
|
||||
SET_TARGET_PROPERTIES (starbound PROPERTIES XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES)
|
||||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES (starbound ${STAR_EXT_LIBS} ${STAR_EXT_GUI_LIBS})
|
@ -22,7 +22,9 @@
|
||||
#include "StarInterfaceLuaBindings.hpp"
|
||||
#include "StarInputLuaBindings.hpp"
|
||||
#include "StarVoiceLuaBindings.hpp"
|
||||
#include "StarCameraLuaBindings.hpp"
|
||||
#include "StarClipboardLuaBindings.hpp"
|
||||
#include "StarRenderingLuaBindings.hpp"
|
||||
|
||||
#if defined STAR_SYSTEM_WINDOWS
|
||||
#include <windows.h>
|
||||
@ -404,6 +406,7 @@ void ClientApplication::render() {
|
||||
auto size = Vec2F(renderer->screenSize());
|
||||
auto quad = renderFlatRect(RectF::withSize(size / -2, size), Vec4B::filled(0), 0.0f);
|
||||
for (auto& layer : m_postProcessLayers) {
|
||||
if (layer.group ? layer.group->enabled : true) {
|
||||
for (unsigned i = 0; i < layer.passes; i++) {
|
||||
for (auto& effect : layer.effects) {
|
||||
renderer->switchEffectConfig(effect);
|
||||
@ -412,6 +415,7 @@ void ClientApplication::render() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
renderer->switchEffectConfig("interface");
|
||||
auto start = Time::monotonicMicroseconds();
|
||||
m_mainInterface->renderInWorldElements();
|
||||
@ -433,6 +437,8 @@ void ClientApplication::getAudioData(int16_t* sampleData, size_t frameCount) {
|
||||
}
|
||||
}
|
||||
|
||||
auto postProcessGroupsRoot = "postProcessGroups";
|
||||
|
||||
void ClientApplication::renderReload() {
|
||||
auto assets = m_root->assets();
|
||||
auto renderer = Application::renderer();
|
||||
@ -463,18 +469,55 @@ void ClientApplication::renderReload() {
|
||||
|
||||
loadEffectConfig("world");
|
||||
|
||||
// define post process groups and set them to be enabled/disabled based on config
|
||||
|
||||
auto config = m_root->configuration();
|
||||
if (!config->get(postProcessGroupsRoot).isType(Json::Type::Object))
|
||||
config->set(postProcessGroupsRoot, JsonObject());
|
||||
auto groupsConfig = config->get(postProcessGroupsRoot);
|
||||
|
||||
m_postProcessGroups.clear();
|
||||
auto postProcessGroups = assets->json("/client.config:postProcessGroups").toObject();
|
||||
for (auto& pair : postProcessGroups) {
|
||||
auto name = pair.first;
|
||||
auto groupConfig = groupsConfig.opt(name);
|
||||
auto def = pair.second.getBool("enabledDefault",true);
|
||||
if (!groupConfig)
|
||||
config->setPath(strf("{}.{}", postProcessGroupsRoot, name),JsonObject());
|
||||
m_postProcessGroups.add(name,PostProcessGroup{ groupConfig ? groupConfig.value().getBool("enabled", def) : def });
|
||||
}
|
||||
|
||||
// define post process layers and optionally assign them to groups
|
||||
m_postProcessLayers.clear();
|
||||
auto postProcessLayers = assets->json("/client.config:postProcessLayers").toArray();
|
||||
for (auto& layer : postProcessLayers) {
|
||||
auto effects = jsonToStringList(layer.getArray("effects"));
|
||||
for (auto& effect : effects)
|
||||
loadEffectConfig(effect);
|
||||
m_postProcessLayers.append(PostProcessLayer{ std::move(effects), (unsigned)layer.getUInt("passes", 1) });
|
||||
PostProcessGroup* group = nullptr;
|
||||
auto gname = layer.optString("group");
|
||||
if (gname) {
|
||||
group = &m_postProcessGroups.get(gname.value());
|
||||
}
|
||||
m_postProcessLayers.append(PostProcessLayer{ std::move(effects), (unsigned)layer.getUInt("passes", 1), group });
|
||||
}
|
||||
|
||||
loadEffectConfig("interface");
|
||||
}
|
||||
|
||||
void ClientApplication::setPostProcessGroupEnabled(String group, bool enabled, Maybe<bool> save) {
|
||||
m_postProcessGroups.get(group).enabled = enabled;
|
||||
if (save && save.value())
|
||||
m_root->configuration()->setPath(strf("{}.{}.enabled", postProcessGroupsRoot, group),enabled);
|
||||
}
|
||||
bool ClientApplication::postProcessGroupEnabled(String group) {
|
||||
return m_postProcessGroups.get(group).enabled;
|
||||
}
|
||||
|
||||
Json ClientApplication::postProcessGroups() {
|
||||
return m_root->assets()->json("/client.config:postProcessGroups");
|
||||
}
|
||||
|
||||
void ClientApplication::changeState(MainAppState newState) {
|
||||
MainAppState oldState = m_state;
|
||||
m_state = newState;
|
||||
@ -541,8 +584,11 @@ void ClientApplication::changeState(MainAppState newState) {
|
||||
|
||||
m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks());
|
||||
m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks());
|
||||
if (!m_root->configuration()->get("safeScripts").toBool())
|
||||
m_universeClient->setLuaCallbacks("clipboard", LuaBindings::makeClipboardCallbacks(appController()));
|
||||
m_universeClient->setLuaCallbacks("camera", LuaBindings::makeCameraCallbacks(&m_worldPainter->camera()));
|
||||
m_universeClient->setLuaCallbacks("renderer", LuaBindings::makeRenderingCallbacks(this));
|
||||
|
||||
Json alwaysAllow = m_root->configuration()->getPath("safe.alwaysAllowClipboard");
|
||||
m_universeClient->setLuaCallbacks("clipboard", LuaBindings::makeClipboardCallbacks(appController(), alwaysAllow && alwaysAllow.toBool()));
|
||||
|
||||
auto heldScriptPanes = make_shared<List<MainInterface::ScriptPaneInfo>>();
|
||||
|
||||
@ -565,7 +611,7 @@ void ClientApplication::changeState(MainAppState newState) {
|
||||
};
|
||||
|
||||
m_mainMixer->setUniverseClient(m_universeClient);
|
||||
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer());
|
||||
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer(), m_universeClient);
|
||||
if (auto renderer = Application::renderer())
|
||||
m_titleScreen->renderInit(renderer);
|
||||
}
|
||||
@ -682,8 +728,9 @@ void ClientApplication::changeState(MainAppState newState) {
|
||||
m_mainInterface = make_shared<MainInterface>(m_universeClient, m_worldPainter, m_cinematicOverlay);
|
||||
m_universeClient->setLuaCallbacks("interface", LuaBindings::makeInterfaceCallbacks(m_mainInterface.get()));
|
||||
m_universeClient->setLuaCallbacks("chat", LuaBindings::makeChatCallbacks(m_mainInterface.get(), m_universeClient.get()));
|
||||
m_universeClient->startLua();
|
||||
m_mainInterface->displayDefaultPanes();
|
||||
|
||||
m_universeClient->startLua();
|
||||
m_mainMixer->setWorldPainter(m_worldPainter);
|
||||
|
||||
if (auto renderer = Application::renderer()) {
|
||||
|
@ -18,6 +18,11 @@ STAR_CLASS(Input);
|
||||
STAR_CLASS(Voice);
|
||||
|
||||
class ClientApplication : public Application {
|
||||
public:
|
||||
void setPostProcessGroupEnabled(String group, bool enabled, Maybe<bool> save);
|
||||
bool postProcessGroupEnabled(String group);
|
||||
Json postProcessGroups();
|
||||
|
||||
protected:
|
||||
virtual void startup(StringList const& cmdLineArgs) override;
|
||||
virtual void shutdown() override;
|
||||
@ -53,9 +58,14 @@ private:
|
||||
String password;
|
||||
};
|
||||
|
||||
struct PostProcessGroup {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct PostProcessLayer {
|
||||
List<String> effects;
|
||||
unsigned passes;
|
||||
PostProcessGroup* group;
|
||||
};
|
||||
|
||||
void renderReload();
|
||||
@ -104,6 +114,7 @@ private:
|
||||
WorldRenderData m_renderData;
|
||||
MainInterfacePtr m_mainInterface;
|
||||
|
||||
StringMap<PostProcessGroup> m_postProcessGroups;
|
||||
List<PostProcessLayer> m_postProcessLayers;
|
||||
|
||||
// Valid if main app state == SinglePlayer
|
||||
|
45
source/client/StarRenderingLuaBindings.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "StarRenderingLuaBindings.hpp"
|
||||
#include "StarJsonExtra.hpp"
|
||||
#include "StarLuaConverters.hpp"
|
||||
#include "StarClientApplication.hpp"
|
||||
#include "StarRenderer.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
LuaCallbacks LuaBindings::makeRenderingCallbacks(ClientApplication* app) {
|
||||
LuaCallbacks callbacks;
|
||||
|
||||
// if the last argument is defined and true, this change will also be saved to starbound.config and read on next game start, use for things such as an interface that does this
|
||||
callbacks.registerCallbackWithSignature<void, String, bool, Maybe<bool>>("setPostProcessGroupEnabled", bind(mem_fn(&ClientApplication::setPostProcessGroupEnabled), app, _1, _2, _3));
|
||||
callbacks.registerCallbackWithSignature<bool, String>("postProcessGroupEnabled", bind(mem_fn(&ClientApplication::postProcessGroupEnabled), app, _1));
|
||||
|
||||
|
||||
// not entirely necessary (root.assetJson can achieve the same purpose) but may as well
|
||||
callbacks.registerCallbackWithSignature<Json>("postProcessGroups", bind(mem_fn(&ClientApplication::postProcessGroups), app));
|
||||
|
||||
// typedef Variant<float, int, Vec2F, Vec3F, Vec4F, bool> RenderEffectParameter;
|
||||
// feel free to change this if there's a better way to do this
|
||||
// specifically checks if the effect parameter is an int since Lua prefers converting the values to floats
|
||||
callbacks.registerCallback("setEffectParameter", [app](String const& effectName, String const& effectParameter, RenderEffectParameter const& value) {
|
||||
auto renderer = app->renderer();
|
||||
auto mtype = renderer->getEffectScriptableParameterType(effectName, effectParameter);
|
||||
if (mtype) {
|
||||
auto type = mtype.value();
|
||||
if (type == 1 && value.is<float>()) {
|
||||
renderer->setEffectScriptableParameter(effectName, effectParameter, (int)value.get<float>());
|
||||
} else {
|
||||
renderer->setEffectScriptableParameter(effectName, effectParameter, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
callbacks.registerCallback("getEffectParameter", [app](String const& effectName, String const& effectParameter) {
|
||||
auto renderer = app->renderer();
|
||||
return renderer->getEffectScriptableParameter(effectName, effectParameter);
|
||||
});
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
}
|
13
source/client/StarRenderingLuaBindings.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "StarLua.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
STAR_CLASS(ClientApplication);
|
||||
|
||||
namespace LuaBindings {
|
||||
LuaCallbacks makeRenderingCallbacks(ClientApplication* app);
|
||||
}
|
||||
|
||||
}
|
@ -41,6 +41,7 @@ SET (star_core_HEADERS
|
||||
StarIdMap.hpp
|
||||
StarImage.hpp
|
||||
StarImageProcessing.hpp
|
||||
StarImageScaling.hpp
|
||||
StarInputEvent.hpp
|
||||
StarInterpolation.hpp
|
||||
StarRefPtr.hpp
|
||||
@ -70,10 +71,12 @@ SET (star_core_HEADERS
|
||||
StarMultiArray.hpp
|
||||
StarMultiArrayInterpolator.hpp
|
||||
StarMultiTable.hpp
|
||||
StarNetCompatibility.hpp
|
||||
StarNetElement.hpp
|
||||
StarNetElementBasicFields.hpp
|
||||
StarNetElementContainers.hpp
|
||||
StarNetElementDynamicGroup.hpp
|
||||
StarNetElementExt.hpp
|
||||
StarNetElementFloatFields.hpp
|
||||
StarNetElementGroup.hpp
|
||||
StarNetElementSignal.hpp
|
||||
@ -122,6 +125,7 @@ SET (star_core_HEADERS
|
||||
StarUnicode.hpp
|
||||
StarUuid.hpp
|
||||
StarVector.hpp
|
||||
StarVersion.hpp
|
||||
StarVlqEncoding.hpp
|
||||
StarWeightedPool.hpp
|
||||
StarWorkerPool.hpp
|
||||
@ -149,6 +153,7 @@ SET (star_core_SOURCES
|
||||
StarIODevice.cpp
|
||||
StarImage.cpp
|
||||
StarImageProcessing.cpp
|
||||
StarImageScaling.cpp
|
||||
StarInputEvent.cpp
|
||||
StarJson.cpp
|
||||
StarJsonBuilder.cpp
|
||||
@ -157,11 +162,13 @@ SET (star_core_SOURCES
|
||||
StarJsonPatch.cpp
|
||||
StarJsonRpc.cpp
|
||||
StarFormattedJson.cpp
|
||||
StarLexicalCast.cpp
|
||||
StarListener.cpp
|
||||
StarLogging.cpp
|
||||
StarLua.cpp
|
||||
StarLuaConverters.cpp
|
||||
StarMemory.cpp
|
||||
StarNetCompatibility.cpp
|
||||
StarNetElement.cpp
|
||||
StarNetElementBasicFields.cpp
|
||||
StarNetElementGroup.cpp
|
||||
@ -217,7 +224,8 @@ ELSEIF (STAR_SYSTEM_FAMILY_WINDOWS)
|
||||
|
||||
ENDIF ()
|
||||
|
||||
ADD_LIBRARY (star_core OBJECT ${star_core_SOURCES} ${star_core_HEADERS})
|
||||
CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp)
|
||||
ADD_LIBRARY (star_core OBJECT ${star_core_SOURCES} ${star_core_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp)
|
||||
|
||||
IF(STAR_PRECOMPILED_HEADERS)
|
||||
TARGET_PRECOMPILE_HEADERS (star_core PUBLIC StarPch.hpp)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "StarBTreeDatabase.hpp"
|
||||
#include "StarSha256.hpp"
|
||||
#include "StarVlqEncoding.hpp"
|
||||
#include "StarLogging.hpp"
|
||||
|
||||
namespace Star {
|
||||
|
||||
@ -243,7 +244,7 @@ uint32_t BTreeDatabase::freeBlockCount() {
|
||||
indexBlockIndex = indexBlock.nextFreeBlock;
|
||||
}
|
||||
|
||||
count += m_availableBlocks.size() + m_pendingFree.size();
|
||||
count += m_availableBlocks.size();
|
||||
|
||||
// Include untracked blocks at the end of the file in the free count.
|
||||
count += (m_device->size() - m_deviceSize) / m_blockSize;
|
||||
@ -272,7 +273,7 @@ uint32_t BTreeDatabase::leafBlockCount() {
|
||||
return true;
|
||||
}
|
||||
|
||||
BTreeDatabase* parent;
|
||||
BTreeDatabase* parent = nullptr;
|
||||
BlockIndex leafBlockCount = 0;
|
||||
};
|
||||
|
||||
@ -293,8 +294,8 @@ void BTreeDatabase::rollback() {
|
||||
|
||||
m_availableBlocks.clear();
|
||||
m_indexCache.clear();
|
||||
m_uncommittedWrites.clear();
|
||||
m_uncommitted.clear();
|
||||
m_pendingFree.clear();
|
||||
|
||||
readRoot();
|
||||
|
||||
@ -305,6 +306,7 @@ void BTreeDatabase::rollback() {
|
||||
void BTreeDatabase::close(bool closeDevice) {
|
||||
WriteLocker writeLocker(m_lock);
|
||||
if (m_open) {
|
||||
if (!tryFlatten())
|
||||
doCommit();
|
||||
|
||||
m_indexCache.clear();
|
||||
@ -536,7 +538,7 @@ auto BTreeDatabase::BTreeImpl::loadIndex(Pointer pointer) -> Index {
|
||||
index->pointers.resize(s);
|
||||
for (uint32_t i = 0; i < s; ++i) {
|
||||
auto& e = index->pointers[i];
|
||||
e.key =buffer.readBytes(parent->m_keySize);
|
||||
e.key = buffer.readBytes(parent->m_keySize);
|
||||
e.pointer = buffer.read<BlockIndex>();
|
||||
}
|
||||
|
||||
@ -896,17 +898,25 @@ void BTreeDatabase::rawReadBlock(BlockIndex blockIndex, size_t blockOffset, char
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
if (auto buffer = m_uncommittedWrites.ptr(blockIndex))
|
||||
buffer->copyTo(block, blockOffset, size);
|
||||
else
|
||||
m_device->readFullAbsolute(HeaderSize + blockIndex * (StreamOffset)m_blockSize + blockOffset, block, size);
|
||||
}
|
||||
|
||||
void BTreeDatabase::rawWriteBlock(BlockIndex blockIndex, size_t blockOffset, char const* block, size_t size) const {
|
||||
void BTreeDatabase::rawWriteBlock(BlockIndex blockIndex, size_t blockOffset, char const* block, size_t size) {
|
||||
if (blockOffset > m_blockSize || size > m_blockSize - blockOffset)
|
||||
throw DBException::format("Write past end of block, offset: {} size {}", blockOffset, size);
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
m_device->writeFullAbsolute(HeaderSize + blockIndex * (StreamOffset)m_blockSize + blockOffset, block, size);
|
||||
StreamOffset blockStart = HeaderSize + blockIndex * (StreamOffset)m_blockSize;
|
||||
auto buffer = m_uncommittedWrites.find(blockIndex);
|
||||
if (buffer == m_uncommittedWrites.end())
|
||||
buffer = m_uncommittedWrites.emplace(blockIndex, m_device->readBytesAbsolute(blockStart, m_blockSize)).first;
|
||||
|
||||
buffer->second.writeFrom(block, blockOffset, size);
|
||||
}
|
||||
|
||||
auto BTreeDatabase::readFreeIndexBlock(BlockIndex blockIndex) -> FreeIndexBlock {
|
||||
@ -991,12 +1001,12 @@ auto BTreeDatabase::leafTailBlocks(BlockIndex leafPointer) -> List<BlockIndex> {
|
||||
}
|
||||
|
||||
void BTreeDatabase::freeBlock(BlockIndex b) {
|
||||
if (m_uncommitted.contains(b)) {
|
||||
if (m_uncommitted.contains(b))
|
||||
m_uncommitted.remove(b);
|
||||
if (m_uncommittedWrites.contains(b))
|
||||
m_uncommittedWrites.remove(b);
|
||||
|
||||
m_availableBlocks.add(b);
|
||||
} else {
|
||||
m_pendingFree.append(b);
|
||||
}
|
||||
}
|
||||
|
||||
auto BTreeDatabase::reserveBlock() -> BlockIndex {
|
||||
@ -1007,10 +1017,7 @@ auto BTreeDatabase::reserveBlock() -> BlockIndex {
|
||||
FreeIndexBlock indexBlock = readFreeIndexBlock(m_headFreeIndexBlock);
|
||||
for (auto const& b : indexBlock.freeBlocks)
|
||||
m_availableBlocks.add(b);
|
||||
// We cannot make available the block itself, because we must maintain
|
||||
// atomic consistency. We will need to free this block later and commit
|
||||
// the new free index block chain.
|
||||
m_pendingFree.append(m_headFreeIndexBlock);
|
||||
m_availableBlocks.add(m_headFreeIndexBlock);
|
||||
m_headFreeIndexBlock = indexBlock.nextFreeBlock;
|
||||
}
|
||||
|
||||
@ -1068,65 +1075,168 @@ void BTreeDatabase::readRoot() {
|
||||
}
|
||||
|
||||
void BTreeDatabase::doCommit() {
|
||||
if (m_availableBlocks.empty() && m_pendingFree.empty() && m_uncommitted.empty())
|
||||
if (m_availableBlocks.empty() && m_uncommitted.empty())
|
||||
return;
|
||||
|
||||
if (!m_availableBlocks.empty() || !m_pendingFree.empty()) {
|
||||
if (!m_availableBlocks.empty()) {
|
||||
// First, read the existing head FreeIndexBlock, if it exists
|
||||
FreeIndexBlock indexBlock = FreeIndexBlock{InvalidBlockIndex, {}};
|
||||
if (m_headFreeIndexBlock != InvalidBlockIndex) {
|
||||
indexBlock = readFreeIndexBlock(m_headFreeIndexBlock);
|
||||
if (indexBlock.freeBlocks.size() >= maxFreeIndexLength()) {
|
||||
// If the existing head free index block is full, then we should start a
|
||||
// new one and leave it alone
|
||||
indexBlock.nextFreeBlock = m_headFreeIndexBlock;
|
||||
indexBlock.freeBlocks.clear();
|
||||
} else {
|
||||
// If we are copying an existing free index block, the old free index
|
||||
// block will be a newly freed block
|
||||
indexBlock.freeBlocks.append(m_headFreeIndexBlock);
|
||||
}
|
||||
}
|
||||
|
||||
// Then, we need to write all the available blocks, which are safe to write
|
||||
// to, and the pending free blocks, which are NOT safe to write to, to the
|
||||
// FreeIndexBlock chain.
|
||||
while (true) {
|
||||
if (indexBlock.freeBlocks.size() < maxFreeIndexLength() && (!m_availableBlocks.empty() || !m_pendingFree.empty())) {
|
||||
// If we have room on our current FreeIndexblock, just add a block to
|
||||
// it. Prioritize the pending free blocks, because we cannot use those
|
||||
// to write to.
|
||||
BlockIndex toAdd;
|
||||
if (m_pendingFree.empty())
|
||||
toAdd = m_availableBlocks.takeFirst();
|
||||
auto newBlock = [&]() -> BlockIndex {
|
||||
if (!m_availableBlocks.empty())
|
||||
return m_availableBlocks.takeFirst();
|
||||
else
|
||||
toAdd = m_pendingFree.takeFirst();
|
||||
return makeEndBlock();
|
||||
};
|
||||
|
||||
if (m_headFreeIndexBlock != InvalidBlockIndex)
|
||||
indexBlock = readFreeIndexBlock(m_headFreeIndexBlock);
|
||||
else
|
||||
m_headFreeIndexBlock = newBlock();
|
||||
|
||||
// Then, we need to write all the available blocks to the FreeIndexBlock chain.
|
||||
while (true) {
|
||||
// If we have room on our current FreeIndexBlock, just add a block to it.
|
||||
if (!m_availableBlocks.empty() && indexBlock.freeBlocks.size() < maxFreeIndexLength()) {
|
||||
BlockIndex toAdd = m_availableBlocks.takeFirst();
|
||||
indexBlock.freeBlocks.append(toAdd);
|
||||
} else {
|
||||
// If our index block is full OR we are out of blocks to free, then
|
||||
// need to write a new head free index block.
|
||||
if (m_availableBlocks.empty())
|
||||
m_headFreeIndexBlock = makeEndBlock();
|
||||
else
|
||||
m_headFreeIndexBlock = m_availableBlocks.takeFirst();
|
||||
// Update the current head free index block.
|
||||
writeFreeIndexBlock(m_headFreeIndexBlock, indexBlock);
|
||||
|
||||
// If we're out of blocks to free, then we're done
|
||||
if (m_availableBlocks.empty() && m_pendingFree.empty())
|
||||
if (m_availableBlocks.empty())
|
||||
break;
|
||||
|
||||
// If our head free index block is full, then
|
||||
// need to write a new head free index block.
|
||||
if (indexBlock.freeBlocks.size() >= maxFreeIndexLength()) {
|
||||
indexBlock.nextFreeBlock = m_headFreeIndexBlock;
|
||||
indexBlock.freeBlocks.clear();
|
||||
|
||||
m_headFreeIndexBlock = newBlock();
|
||||
writeFreeIndexBlock(m_headFreeIndexBlock, indexBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
commitWrites();
|
||||
writeRoot();
|
||||
|
||||
m_uncommitted.clear();
|
||||
}
|
||||
|
||||
void BTreeDatabase::commitWrites() {
|
||||
for (auto& write : m_uncommittedWrites)
|
||||
m_device->writeFullAbsolute(HeaderSize + write.first * (StreamOffset)m_blockSize, write.second.ptr(), m_blockSize);
|
||||
|
||||
m_device->sync();
|
||||
m_uncommittedWrites.clear();
|
||||
}
|
||||
|
||||
bool BTreeDatabase::tryFlatten() {
|
||||
if (m_headFreeIndexBlock == InvalidBlockIndex || m_rootIsLeaf || !m_device->isWritable())
|
||||
return false;
|
||||
|
||||
BlockIndex freeBlockCount = 0;
|
||||
BlockIndex indexBlockIndex = m_headFreeIndexBlock;
|
||||
while (indexBlockIndex != InvalidBlockIndex) {
|
||||
FreeIndexBlock indexBlock = readFreeIndexBlock(indexBlockIndex);
|
||||
freeBlockCount += 1 + indexBlock.freeBlocks.size();
|
||||
indexBlockIndex = indexBlock.nextFreeBlock;
|
||||
}
|
||||
|
||||
BlockIndex expectedBlockCount = (m_deviceSize - HeaderSize) / m_blockSize;
|
||||
float free = float(freeBlockCount) / float(expectedBlockCount);
|
||||
if (free < 0.05f)
|
||||
return false;
|
||||
|
||||
Logger::info("[BTreeDatabase] File '{}' is {:.2f}% free space, flattening", m_device->deviceName(), free * 100.f);
|
||||
|
||||
indexBlockIndex = m_headFreeIndexBlock;
|
||||
{
|
||||
List<BlockIndex> availableBlocksList;
|
||||
do {
|
||||
FreeIndexBlock indexBlock = readFreeIndexBlock(indexBlockIndex);
|
||||
availableBlocksList.appendAll(indexBlock.freeBlocks);
|
||||
availableBlocksList.append(indexBlockIndex);
|
||||
indexBlockIndex = indexBlock.nextFreeBlock;
|
||||
} while (indexBlockIndex != InvalidBlockIndex);
|
||||
m_headFreeIndexBlock = InvalidBlockIndex;
|
||||
|
||||
sort(availableBlocksList);
|
||||
for (auto& availableBlock : availableBlocksList)
|
||||
m_availableBlocks.insert(m_availableBlocks.end(), availableBlock);
|
||||
}
|
||||
|
||||
BlockIndex count = 1; // 1 to include root index
|
||||
|
||||
double start = Time::monotonicTime();
|
||||
auto index = m_impl.loadIndex(m_impl.rootPointer());
|
||||
if (flattenVisitor(index, count)) {
|
||||
m_impl.deleteIndex(index);
|
||||
index->self = InvalidBlockIndex;
|
||||
m_root = m_impl.storeIndex(index);
|
||||
}
|
||||
|
||||
m_availableBlocks.clear();
|
||||
m_device->resize(m_deviceSize = HeaderSize + (StreamOffset)m_blockSize * count);
|
||||
|
||||
m_indexCache.clear();
|
||||
commitWrites();
|
||||
writeRoot();
|
||||
m_uncommitted.clear();
|
||||
|
||||
Logger::info("[BTreeDatabase] Finished flattening '{}' in {:.2f} milliseconds", m_device->deviceName(), (Time::monotonicTime() - start) * 1000.f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BTreeDatabase::flattenVisitor(BTreeImpl::Index& index, BlockIndex& count) {
|
||||
auto pointerCount = index->pointerCount();
|
||||
count += pointerCount;
|
||||
bool canStore = !m_availableBlocks.empty();
|
||||
|
||||
bool needsStore = false;
|
||||
if (m_impl.indexLevel(index) == 0) {
|
||||
for (size_t i = 0; i != pointerCount; ++i) {
|
||||
auto indexPointer = index->pointer(i);
|
||||
auto tailBlocks = leafTailBlocks(indexPointer);
|
||||
if (canStore) {
|
||||
bool leafNeedsStore = m_availableBlocks.first() < indexPointer;
|
||||
|
||||
if (!leafNeedsStore)
|
||||
for (size_t i = 0; !leafNeedsStore && i != tailBlocks.size(); ++i)
|
||||
if (m_availableBlocks.first() < tailBlocks[i])
|
||||
leafNeedsStore = true;
|
||||
|
||||
if (leafNeedsStore) {
|
||||
auto leaf = m_impl.loadLeaf(indexPointer);
|
||||
m_impl.deleteLeaf(leaf);
|
||||
leaf->self = InvalidBlockIndex;
|
||||
index->updatePointer(i, m_impl.storeLeaf(leaf));
|
||||
tailBlocks = leafTailBlocks(leaf->self);
|
||||
needsStore = true;
|
||||
}
|
||||
canStore = !m_availableBlocks.empty();
|
||||
}
|
||||
count += tailBlocks.size();
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i != pointerCount; ++i) {
|
||||
auto childIndex = m_impl.loadIndex(index->pointer(i));
|
||||
if (canStore && flattenVisitor(childIndex, count)) {
|
||||
m_impl.deleteIndex(childIndex);
|
||||
childIndex->self = InvalidBlockIndex;
|
||||
index->updatePointer(i, m_impl.storeIndex(childIndex));
|
||||
canStore = !m_availableBlocks.empty();
|
||||
needsStore = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return needsStore || (canStore && m_availableBlocks.first() < index->self);
|
||||
}
|
||||
|
||||
void BTreeDatabase::checkIfOpen(char const* methodName, bool shouldBeOpen) const {
|
||||
if (shouldBeOpen && !m_open)
|
||||
throw DBException::format("BTreeDatabase method '{}' called when not open, must be open.", methodName);
|
||||
@ -1146,7 +1256,7 @@ void BTreeDatabase::checkKeySize(ByteArray const& k) const {
|
||||
}
|
||||
|
||||
uint32_t BTreeDatabase::maxFreeIndexLength() const {
|
||||
return (m_blockSize - 2 - sizeof(BlockIndex) - 4) / sizeof(BlockIndex);
|
||||
return (m_blockSize / sizeof(BlockIndex)) - 2 - sizeof(BlockIndex) - 4;
|
||||
}
|
||||
|
||||
BTreeSha256Database::BTreeSha256Database() {
|
||||
|
@ -230,7 +230,7 @@ private:
|
||||
void updateBlock(BlockIndex blockIndex, ByteArray const& block);
|
||||
|
||||
void rawReadBlock(BlockIndex blockIndex, size_t blockOffset, char* block, size_t size) const;
|
||||
void rawWriteBlock(BlockIndex blockIndex, size_t blockOffset, char const* block, size_t size) const;
|
||||
void rawWriteBlock(BlockIndex blockIndex, size_t blockOffset, char const* block, size_t size);
|
||||
|
||||
void updateHeadFreeIndexBlock(BlockIndex newHead);
|
||||
|
||||
@ -251,6 +251,9 @@ private:
|
||||
void writeRoot();
|
||||
void readRoot();
|
||||
void doCommit();
|
||||
void commitWrites();
|
||||
bool tryFlatten();
|
||||
bool flattenVisitor(BTreeImpl::Index& index, BlockIndex& count);
|
||||
|
||||
void checkIfOpen(char const* methodName, bool shouldBeOpen) const;
|
||||
void checkBlockIndex(size_t blockIndex) const;
|
||||
@ -285,14 +288,14 @@ private:
|
||||
bool m_dirty;
|
||||
|
||||
// Blocks that can be freely allocated and written to without violating
|
||||
// atomic consistency
|
||||
// atomic consistency.
|
||||
Set<BlockIndex> m_availableBlocks;
|
||||
|
||||
// Blocks to be freed on next commit.
|
||||
Deque<BlockIndex> m_pendingFree;
|
||||
|
||||
// Blocks that have been written in uncommitted portions of the tree.
|
||||
Set<BlockIndex> m_uncommitted;
|
||||
|
||||
// Temporarily holds written data so that it can be rolled back.
|
||||
mutable Map<BlockIndex, ByteArray> m_uncommittedWrites;
|
||||
};
|
||||
|
||||
// Version of BTreeDatabase that hashes keys with SHA-256 to produce a unique
|
||||
|
@ -322,6 +322,8 @@ Vec3F Color::toRgbF() const {
|
||||
return Vec3F(redF(), greenF(), blueF());
|
||||
}
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("-fno-fast-math")
|
||||
Vec4F Color::toHsva() const {
|
||||
float h, s, v;
|
||||
|
||||
@ -365,6 +367,7 @@ Vec4F Color::toHsva() const {
|
||||
|
||||
return Vec4F(h, s, v, alphaF());
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
String Color::toHex() const {
|
||||
auto rgba = toRgba();
|
||||
|