mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-26 06:40:22 +00:00
Merge branch 'master' of https://gitlab.com/Kuyondo/openmw
This commit is contained in:
commit
071793eeb3
50
.github/workflows/cmake.yml
vendored
Normal file
50
.github/workflows/cmake.yml
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
name: CMake
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: RelWithDebInfo
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Add OpenMW PPA Dependancies
|
||||||
|
run: sudo add-apt-repository ppa:openmw/openmw; sudo apt-get update
|
||||||
|
|
||||||
|
- name: Install Building Dependancies
|
||||||
|
run: sudo CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
|
||||||
|
|
||||||
|
- name: Prime ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1
|
||||||
|
with:
|
||||||
|
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
||||||
|
max-size: 1000M
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
shell: bash
|
||||||
|
run: cmake --install .
|
||||||
|
|
||||||
|
- name: Create Artifact
|
||||||
|
shell: bash
|
||||||
|
working-directory: install
|
||||||
|
run: |
|
||||||
|
ls -laR
|
||||||
|
7z a ../build_artifact.7z .
|
||||||
|
|
||||||
|
- name: Upload Artifact
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
path: ./build_artifact.7z
|
||||||
|
name: build_artifact.7z
|
@ -31,6 +31,23 @@ stages:
|
|||||||
paths:
|
paths:
|
||||||
- build/install/
|
- build/install/
|
||||||
|
|
||||||
|
Clang_Tidy:
|
||||||
|
extends: .Debian_Image
|
||||||
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||||
|
before_script:
|
||||||
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic clang-tidy clang
|
||||||
|
script:
|
||||||
|
- CI/before_script.linux.sh
|
||||||
|
- cd build
|
||||||
|
- cmake --build . -- -j $(nproc) openmw esmtool bsatool niftest openmw-wizard openmw-launcher openmw-iniimporter openmw-essimporter
|
||||||
|
variables:
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
CI_CLANG_TIDY: 1
|
||||||
|
timeout: 8h
|
||||||
|
|
||||||
Coverity:
|
Coverity:
|
||||||
extends: .Debian_Image
|
extends: .Debian_Image
|
||||||
stage: build
|
stage: build
|
||||||
@ -42,8 +59,8 @@ Coverity:
|
|||||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||||
script:
|
script:
|
||||||
- CI/before_script.linux.sh
|
- CI/before_script.linux.sh
|
||||||
# Add more than just `openmw` once we can build everything under 3h
|
# Remove the specific targets and build everything once we can do it under 3h
|
||||||
- cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) openmw
|
- cov-analysis-linux64-*/bin/cov-build --dir cov-int cmake --build build -- -j $(nproc) openmw esmtool bsatool niftest openmw-wizard openmw-launcher openmw-iniimporter openmw-essimporter
|
||||||
after_script:
|
after_script:
|
||||||
- tar cfz cov-int.tar.gz cov-int
|
- tar cfz cov-int.tar.gz cov-int
|
||||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||||
@ -53,7 +70,7 @@ Coverity:
|
|||||||
variables:
|
variables:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
timeout: 8h
|
artifacts:
|
||||||
|
|
||||||
Debian_GCC:
|
Debian_GCC:
|
||||||
extends: .Debian
|
extends: .Debian
|
||||||
@ -76,6 +93,15 @@ Debian_GCC_tests:
|
|||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
|
Debian_GCC_tests_Debug:
|
||||||
|
extends: Debian_GCC
|
||||||
|
cache:
|
||||||
|
key: Debian_GCC_tests_Debug.v1
|
||||||
|
variables:
|
||||||
|
CCACHE_SIZE: 1G
|
||||||
|
BUILD_TESTS_ONLY: 1
|
||||||
|
CMAKE_BUILD_TYPE: Debug
|
||||||
|
|
||||||
Debian_GCC_Static_Deps:
|
Debian_GCC_Static_Deps:
|
||||||
extends: Debian_GCC
|
extends: Debian_GCC
|
||||||
cache:
|
cache:
|
||||||
@ -88,6 +114,7 @@ Debian_GCC_Static_Deps:
|
|||||||
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-static
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-static
|
||||||
variables:
|
variables:
|
||||||
CI_OPENMW_USE_STATIC_DEPS: 1
|
CI_OPENMW_USE_STATIC_DEPS: 1
|
||||||
|
timeout: 3h
|
||||||
|
|
||||||
Debian_GCC_Static_Deps_tests:
|
Debian_GCC_Static_Deps_tests:
|
||||||
extends: Debian_GCC_Static_Deps
|
extends: Debian_GCC_Static_Deps
|
||||||
@ -118,6 +145,15 @@ Debian_Clang_tests:
|
|||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
|
||||||
|
Debian_Clang_tests_Debug:
|
||||||
|
extends: Debian_Clang
|
||||||
|
cache:
|
||||||
|
key: Debian_Clang_tests_Debug.v1
|
||||||
|
variables:
|
||||||
|
CCACHE_SIZE: 1G
|
||||||
|
BUILD_TESTS_ONLY: 1
|
||||||
|
CMAKE_BUILD_TYPE: Debug
|
||||||
|
|
||||||
.MacOS:
|
.MacOS:
|
||||||
image: macos-11-xcode-12
|
image: macos-11-xcode-12
|
||||||
tags:
|
tags:
|
||||||
@ -187,6 +223,18 @@ variables: &tests-targets
|
|||||||
- choco install ninja -y
|
- choco install ninja -y
|
||||||
- choco install python -y
|
- choco install python -y
|
||||||
- refreshenv
|
- refreshenv
|
||||||
|
- |
|
||||||
|
function Make-SafeFileName {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[String]
|
||||||
|
$FileName
|
||||||
|
)
|
||||||
|
[IO.Path]::GetInvalidFileNameChars() | ForEach-Object {
|
||||||
|
$FileName = $FileName.Replace($_, '_')
|
||||||
|
}
|
||||||
|
return $FileName
|
||||||
|
}
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
- $time = (Get-Date -Format "HH:mm:ss")
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
@ -198,12 +246,13 @@ variables: &tests-targets
|
|||||||
- cmake --build . --config $config --target ($targets.Split(','))
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
- cd $config
|
- cd $config
|
||||||
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
|
- Get-ChildItem -Recurse *.ilk | Remove-Item
|
||||||
- |
|
- |
|
||||||
if (Get-ChildItem -Recurse *.pdb) {
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
}
|
}
|
||||||
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||||
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
||||||
after_script:
|
after_script:
|
||||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
@ -289,6 +338,18 @@ Windows_Ninja_Tests_RelWithDebInfo:
|
|||||||
- choco install vswhere -y
|
- choco install vswhere -y
|
||||||
- choco install python -y
|
- choco install python -y
|
||||||
- refreshenv
|
- refreshenv
|
||||||
|
- |
|
||||||
|
function Make-SafeFileName {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[String]
|
||||||
|
$FileName
|
||||||
|
)
|
||||||
|
[IO.Path]::GetInvalidFileNameChars() | ForEach-Object {
|
||||||
|
$FileName = $FileName.Replace($_, '_')
|
||||||
|
}
|
||||||
|
return $FileName
|
||||||
|
}
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
- $time = (Get-Date -Format "HH:mm:ss")
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
@ -299,12 +360,13 @@ Windows_Ninja_Tests_RelWithDebInfo:
|
|||||||
- cmake --build . --config $config --target ($targets.Split(','))
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
- cd $config
|
- cd $config
|
||||||
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
|
- Get-ChildItem -Recurse *.ilk | Remove-Item
|
||||||
- |
|
- |
|
||||||
if (Get-ChildItem -Recurse *.pdb) {
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
}
|
}
|
||||||
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||||
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
||||||
after_script:
|
after_script:
|
||||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
@ -412,3 +474,4 @@ Debian_AndroidNDK_arm64-v8a:
|
|||||||
- build/install/
|
- build/install/
|
||||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||||
timeout: 1h30m
|
timeout: 1h30m
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ Programmers
|
|||||||
Austin Salgat (Salgat)
|
Austin Salgat (Salgat)
|
||||||
Ben Shealy (bentsherman)
|
Ben Shealy (bentsherman)
|
||||||
Berulacks
|
Berulacks
|
||||||
|
Bo Svensson
|
||||||
Britt Mathis (galdor557)
|
Britt Mathis (galdor557)
|
||||||
Capostrophic
|
Capostrophic
|
||||||
Carl Maxwell
|
Carl Maxwell
|
||||||
@ -79,6 +80,7 @@ Programmers
|
|||||||
Federico Guerra (FedeWar)
|
Federico Guerra (FedeWar)
|
||||||
Fil Krynicki (filkry)
|
Fil Krynicki (filkry)
|
||||||
Finbar Crago (finbar-crago)
|
Finbar Crago (finbar-crago)
|
||||||
|
Florent Teppe (Tetramir)
|
||||||
Florian Weber (Florianjw)
|
Florian Weber (Florianjw)
|
||||||
Frédéric Chardon (fr3dz10)
|
Frédéric Chardon (fr3dz10)
|
||||||
Gaëtan Dezeiraud (Brouilles)
|
Gaëtan Dezeiraud (Brouilles)
|
||||||
@ -99,6 +101,7 @@ Programmers
|
|||||||
James Stephens (james-h-stephens)
|
James Stephens (james-h-stephens)
|
||||||
Jan-Peter Nilsson (peppe)
|
Jan-Peter Nilsson (peppe)
|
||||||
Jan Borsodi (am0s)
|
Jan Borsodi (am0s)
|
||||||
|
JanuarySnow
|
||||||
Jason Hooks (jhooks)
|
Jason Hooks (jhooks)
|
||||||
jeaye
|
jeaye
|
||||||
jefetienne
|
jefetienne
|
||||||
@ -159,6 +162,7 @@ Programmers
|
|||||||
Nikolay Kasyanov (corristo)
|
Nikolay Kasyanov (corristo)
|
||||||
nobrakal
|
nobrakal
|
||||||
Nolan Poe (nopoe)
|
Nolan Poe (nopoe)
|
||||||
|
Nurivan Gomez (Nuri-G)
|
||||||
Oleg Chkan (mrcheko)
|
Oleg Chkan (mrcheko)
|
||||||
Paul Cercueil (pcercuei)
|
Paul Cercueil (pcercuei)
|
||||||
Paul McElroy (Greendogo)
|
Paul McElroy (Greendogo)
|
||||||
@ -225,6 +229,7 @@ Programmers
|
|||||||
Yuri Krupenin
|
Yuri Krupenin
|
||||||
zelurker
|
zelurker
|
||||||
Noah Gooder
|
Noah Gooder
|
||||||
|
Andrew Appuhamy (andrew-app)
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
53
CHANGELOG.md
53
CHANGELOG.md
@ -1,28 +1,80 @@
|
|||||||
0.48.0
|
0.48.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
Bug #1751: Birthsign abilities increase modified attribute values instead of base ones
|
||||||
|
Bug #3246: ESSImporter: Most NPCs are dead on save load
|
||||||
|
Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear
|
||||||
Bug #3737: Scripts from The Underground 2 .esp do not play (all patched versions)
|
Bug #3737: Scripts from The Underground 2 .esp do not play (all patched versions)
|
||||||
Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes
|
Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes
|
||||||
Bug #3905: Great House Dagoth issues
|
Bug #3905: Great House Dagoth issues
|
||||||
|
Bug #4203: Resurrecting an actor should close the loot GUI
|
||||||
|
Bug #4602: Robert's Bodies: crash inside createInstance()
|
||||||
|
Bug #4700: Editor: Incorrect command implementation
|
||||||
|
Bug #4744: Invisible particles must still be processed
|
||||||
|
Bug #5100: Persuasion doesn't always clamp the resulting disposition
|
||||||
Bug #5120: Scripted object spawning updates physics system
|
Bug #5120: Scripted object spawning updates physics system
|
||||||
|
Bug #5207: Loose summons can be present in scene
|
||||||
Bug #5379: Wandering NPCs falling through cantons
|
Bug #5379: Wandering NPCs falling through cantons
|
||||||
Bug #5453: Magic effect VFX are offset for creatures
|
Bug #5453: Magic effect VFX are offset for creatures
|
||||||
Bug #5483: AutoCalc flag is not used to calculate spells cost
|
Bug #5483: AutoCalc flag is not used to calculate spells cost
|
||||||
|
Bug #5508: Engine binary links to Qt without using it
|
||||||
|
Bug #5596: Effects in constant spells should not be merged
|
||||||
|
Bug #5621: Drained stats cannot be restored
|
||||||
|
Bug #5755: Active grid object paging - disappearing textures
|
||||||
|
Bug #5766: Active grid object paging - disappearing textures
|
||||||
|
Bug #5788: Texture editing parses the selected indexes wrongly
|
||||||
|
Bug #5801: A multi-effect spell with the intervention effects and recall always favors Almsivi intervention
|
||||||
|
Bug #5842: GetDisposition adds temporary disposition change from different actors
|
||||||
|
Bug #5863: GetEffect should return true after the player has teleported
|
||||||
Bug #6037: Morrowind Content Language Cannot be Set to English in OpenMW Launcher
|
Bug #6037: Morrowind Content Language Cannot be Set to English in OpenMW Launcher
|
||||||
|
Bug #6051: NaN water height in ESM file is not handled gracefully
|
||||||
Bug #6066: addtopic "return" does not work from within script. No errors thrown
|
Bug #6066: addtopic "return" does not work from within script. No errors thrown
|
||||||
Bug #6067: esp loader fails in for certain subrecord orders
|
Bug #6067: esp loader fails in for certain subrecord orders
|
||||||
|
Bug #6087: Bound items added directly to the inventory disappear if their corresponding spell effect ends
|
||||||
Bug #6101: Disarming trapped unlocked owned objects isn't considered a crime
|
Bug #6101: Disarming trapped unlocked owned objects isn't considered a crime
|
||||||
Bug #6107: Fatigue is incorrectly recalculated when fortify effect is applied or removed
|
Bug #6107: Fatigue is incorrectly recalculated when fortify effect is applied or removed
|
||||||
Bug #6115: Showmap overzealous matching
|
Bug #6115: Showmap overzealous matching
|
||||||
|
Bug #6118: Creature landing sound counts as a footstep
|
||||||
Bug #6123: NPC with broken script freezes the game on hello
|
Bug #6123: NPC with broken script freezes the game on hello
|
||||||
Bug #6129: Player avatar not displayed correctly for large window sizes when GUI scaling active
|
Bug #6129: Player avatar not displayed correctly for large window sizes when GUI scaling active
|
||||||
Bug #6131: Item selection in the avatar window not working correctly for large window sizes
|
Bug #6131: Item selection in the avatar window not working correctly for large window sizes
|
||||||
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
||||||
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
||||||
|
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
||||||
|
Bug #6172: Some creatures can't open doors
|
||||||
|
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
||||||
|
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
||||||
|
Bug #6197: Infinite Casting Loop
|
||||||
|
Bug #6223: Some Constant Effect Bound Items inconsistencies
|
||||||
|
Bug #6273: Respawning NPCs rotation is inconsistent
|
||||||
|
Bug #6282: Laura craft doesn't follow the player character
|
||||||
|
Bug #6283: Avis Dorsey follows you after her death
|
||||||
|
Bug #6289: Keyword search in dialogues expected the text to be all ASCII characters
|
||||||
|
Bug #6302: Teleporting disabled actor breaks its disabled state
|
||||||
|
Bug #6307: Pathfinding in Infidelities quest from Tribunal addon is broken
|
||||||
|
Feature #890: OpenMW-CS: Column filtering
|
||||||
|
Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record
|
||||||
Feature #2780: A way to see current OpenMW version in the console
|
Feature #2780: A way to see current OpenMW version in the console
|
||||||
|
Feature #3616: Allow Zoom levels on the World Map
|
||||||
|
Feature #4297: Implement APPLIED_ONCE flag for magic effects
|
||||||
|
Feature #4414: Handle duration of EXTRA SPELL magic effect
|
||||||
|
Feature #4595: Unique object identifier
|
||||||
|
Feature #4737: Handle instance move from one cell to another
|
||||||
|
Feature #5198: Implement "Magic effect expired" event
|
||||||
|
Feature #5454: Clear active spells from actor when he disappears from scene
|
||||||
Feature #5489: MCP: Telekinesis fix for activators
|
Feature #5489: MCP: Telekinesis fix for activators
|
||||||
|
Feature #5737: Handle instance move from one cell to another
|
||||||
Feature #5996: Support Lua scripts in OpenMW
|
Feature #5996: Support Lua scripts in OpenMW
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
|
Feature #6032: Reverse-z depth buffer
|
||||||
|
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
||||||
|
Feature #6199: Support FBO Rendering
|
||||||
|
Feature #6249: Alpha testing support for Collada
|
||||||
|
Feature #6251: OpenMW-CS: Set instance movement based on camera zoom
|
||||||
|
Feature #6288: Preserve the "blocked" record flag for referenceable objects.
|
||||||
|
Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings
|
||||||
|
Task #6264: Remove the old classes in animation.cpp
|
||||||
|
|
||||||
|
|
||||||
0.47.0
|
0.47.0
|
||||||
------
|
------
|
||||||
@ -1930,6 +1982,7 @@
|
|||||||
Bug #2025: Missing mouse-over text for non affordable items
|
Bug #2025: Missing mouse-over text for non affordable items
|
||||||
Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
|
Bug #2028: [MOD: Tamriel Rebuilt] Crashing when trying to enter interior cell "Ruinous Keep, Great Hall"
|
||||||
Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
|
Bug #2029: Ienith Brothers Thiev's Guild quest journal entry not adding
|
||||||
|
Bug #3066: Editor doesn't check if IDs and other strings are longer than their hardcoded field length
|
||||||
Feature #471: Editor: Special case implementation for top-level window with single sub-window
|
Feature #471: Editor: Special case implementation for top-level window with single sub-window
|
||||||
Feature #472: Editor: Sub-Window re-use settings
|
Feature #472: Editor: Sub-Window re-use settings
|
||||||
Feature #704: Font colors import from fallback settings
|
Feature #704: Font colors import from fallback settings
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
#!/bin/sh -ex
|
#!/bin/sh -ex
|
||||||
|
|
||||||
|
export HOMEBREW_NO_EMOJI=1
|
||||||
|
brew update --quiet
|
||||||
|
|
||||||
# workaround python issue on travis
|
# workaround python issue on travis
|
||||||
[ -z "${TRAVIS}" ] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.8 || true
|
[ -z "${TRAVIS}" ] && brew uninstall --ignore-dependencies python@3.8 || true
|
||||||
[ -z "${TRAVIS}" ] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies python@3.9 || true
|
[ -z "${TRAVIS}" ] && brew uninstall --ignore-dependencies python@3.9 || true
|
||||||
[ -z "${TRAVIS}" ] && HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall --ignore-dependencies qt@6 || true
|
[ -z "${TRAVIS}" ] && brew uninstall --ignore-dependencies qt@6 || true
|
||||||
|
|
||||||
# Some of these tools can come from places other than brew, so check before installing
|
# Some of these tools can come from places other than brew, so check before installing
|
||||||
|
[ -z "${TRAVIS}" ] && brew install fontconfig
|
||||||
command -v ccache >/dev/null 2>&1 || brew install ccache
|
command -v ccache >/dev/null 2>&1 || brew install ccache
|
||||||
command -v cmake >/dev/null 2>&1 || brew install cmake
|
command -v cmake >/dev/null 2>&1 || brew install cmake
|
||||||
command -v qmake >/dev/null 2>&1 || brew install qt@5
|
command -v qmake >/dev/null 2>&1 || brew install qt@5
|
||||||
@ -15,10 +19,6 @@ ccache --version
|
|||||||
cmake --version
|
cmake --version
|
||||||
qmake --version
|
qmake --version
|
||||||
|
|
||||||
brew install lua
|
curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20210716.zip -o ~/openmw-deps.zip
|
||||||
|
|
||||||
curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20210617.zip -o ~/openmw-deps.zip
|
|
||||||
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
||||||
|
|
||||||
# additional libraries
|
|
||||||
[ -z "${TRAVIS}" ] && HOMEBREW_NO_AUTO_UPDATE=1 brew install fontconfig
|
|
||||||
|
@ -14,6 +14,12 @@ if [[ "${BUILD_TESTS_ONLY}" ]]; then
|
|||||||
BUILD_BENCHMARKS=ON
|
BUILD_BENCHMARKS=ON
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
CXX_FLAGS='-Werror -Wno-error=deprecated-declarations -Wno-error=nonnull -Wno-error=deprecated-copy'
|
||||||
|
|
||||||
|
if [[ "${CXX}" == 'clang++' ]]; then
|
||||||
|
CXX_FLAGS="${CXX_FLAGS} -Wno-error=unused-lambda-capture -Wno-error=gnu-zero-variadic-macro-arguments"
|
||||||
|
fi
|
||||||
|
|
||||||
declare -a CMAKE_CONF_OPTS=(
|
declare -a CMAKE_CONF_OPTS=(
|
||||||
-DCMAKE_C_COMPILER="${CC:-/usr/bin/cc}"
|
-DCMAKE_C_COMPILER="${CC:-/usr/bin/cc}"
|
||||||
-DCMAKE_CXX_COMPILER="${CXX:-/usr/bin/c++}"
|
-DCMAKE_CXX_COMPILER="${CXX:-/usr/bin/c++}"
|
||||||
@ -24,6 +30,8 @@ declare -a CMAKE_CONF_OPTS=(
|
|||||||
-DBUILD_SHARED_LIBS=OFF
|
-DBUILD_SHARED_LIBS=OFF
|
||||||
-DUSE_SYSTEM_TINYXML=ON
|
-DUSE_SYSTEM_TINYXML=ON
|
||||||
-DCMAKE_INSTALL_PREFIX=install
|
-DCMAKE_INSTALL_PREFIX=install
|
||||||
|
-DCMAKE_C_FLAGS='-Werror'
|
||||||
|
-DCMAKE_CXX_FLAGS="${CXX_FLAGS}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
||||||
@ -34,6 +42,19 @@ if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
|||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $CI_CLANG_TIDY ]]; then
|
||||||
|
CMAKE_CONF_OPTS+=(
|
||||||
|
-DCMAKE_CXX_CLANG_TIDY='clang-tidy;-checks=-*,boost-*,clang-analyzer-*,concurrency-*,performance-*,-header-filter=.*,bugprone-*,misc-definitions-in-headers,misc-misplaced-const,misc-redundant-expression'
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [[ "${CMAKE_BUILD_TYPE}" ]]; then
|
||||||
|
CMAKE_CONF_OPTS+=(
|
||||||
|
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
|
@ -25,6 +25,5 @@ cmake \
|
|||||||
-D BUILD_BSATOOL=TRUE \
|
-D BUILD_BSATOOL=TRUE \
|
||||||
-D BUILD_ESSIMPORTER=TRUE \
|
-D BUILD_ESSIMPORTER=TRUE \
|
||||||
-D BUILD_NIFTEST=TRUE \
|
-D BUILD_NIFTEST=TRUE \
|
||||||
-D USE_LUAJIT=FALSE \
|
|
||||||
-G"Unix Makefiles" \
|
-G"Unix Makefiles" \
|
||||||
..
|
..
|
||||||
|
@ -29,6 +29,7 @@ declare -rA GROUPED_DEPS=(
|
|||||||
# These dependencies can alternatively be built and linked statically.
|
# These dependencies can alternatively be built and linked statically.
|
||||||
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
||||||
[coverity]="curl"
|
[coverity]="curl"
|
||||||
|
[clang-tidy]="clang-tidy"
|
||||||
|
|
||||||
# Pre-requisites for building MyGUI and OSG for static linking.
|
# Pre-requisites for building MyGUI and OSG for static linking.
|
||||||
#
|
#
|
||||||
|
@ -13,6 +13,11 @@ if(POLICY CMP0083)
|
|||||||
cmake_policy(SET CMP0083 NEW)
|
cmake_policy(SET CMP0083 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# to link with freetype library
|
||||||
|
if(POLICY CMP0079)
|
||||||
|
cmake_policy(SET CMP0079 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
option(OPENMW_GL4ES_MANUAL_INIT "Manually initialize gl4es. This is more reliable on platforms without a windowing system. Requires gl4es to be configured with -DNOEGL=ON -DNO_LOADER=ON -DNO_INIT_CONSTRUCTOR=ON." OFF)
|
option(OPENMW_GL4ES_MANUAL_INIT "Manually initialize gl4es. This is more reliable on platforms without a windowing system. Requires gl4es to be configured with -DNOEGL=ON -DNO_LOADER=ON -DNO_INIT_CONSTRUCTOR=ON." OFF)
|
||||||
if(OPENMW_GL4ES_MANUAL_INIT)
|
if(OPENMW_GL4ES_MANUAL_INIT)
|
||||||
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
|
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
|
||||||
@ -202,8 +207,6 @@ if (USE_QT)
|
|||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5Widgets REQUIRED)
|
||||||
find_package(Qt5Network REQUIRED)
|
find_package(Qt5Network REQUIRED)
|
||||||
find_package(Qt5OpenGL REQUIRED)
|
find_package(Qt5OpenGL REQUIRED)
|
||||||
# Instruct CMake to run moc automatically when needed.
|
|
||||||
#set(CMAKE_AUTOMOC ON)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(USED_OSG_COMPONENTS
|
set(USED_OSG_COMPONENTS
|
||||||
@ -404,11 +407,8 @@ else(USE_LUAJIT)
|
|||||||
add_compile_definitions(NO_LUAJIT)
|
add_compile_definitions(NO_LUAJIT)
|
||||||
endif(USE_LUAJIT)
|
endif(USE_LUAJIT)
|
||||||
|
|
||||||
# Download sol - C++ library binding to Lua
|
# C++ library binding to Lua
|
||||||
file(DOWNLOAD
|
set(SOL_INCLUDE_DIRS ${OpenMW_SOURCE_DIR}/extern/sol3.2.2 ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
||||||
"https://github.com/ThePhD/sol2/releases/download/v3.2.2/sol.hpp" "${OpenMW_BINARY_DIR}/extern/sol3.2.2/sol/sol.hpp"
|
|
||||||
EXPECTED_MD5 ba113cf458f60672917108e69bb4d958)
|
|
||||||
set(SOL_INCLUDE_DIRS ${OpenMW_BINARY_DIR}/extern/sol3.2.2 ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
BEFORE SYSTEM
|
BEFORE SYSTEM
|
||||||
@ -515,7 +515,7 @@ endif()
|
|||||||
|
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -pedantic -Wno-long-long")
|
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wundef -Wno-unused-parameter -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
|
||||||
add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON )
|
add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON )
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
@ -545,7 +545,6 @@ endif()
|
|||||||
|
|
||||||
# Components
|
# Components
|
||||||
add_subdirectory (components)
|
add_subdirectory (components)
|
||||||
target_compile_definitions(components PRIVATE OPENMW_DOC_BASEURL="${OPENMW_DOC_BASEURL}")
|
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
if (BUILD_OPENMW)
|
if (BUILD_OPENMW)
|
||||||
@ -681,7 +680,7 @@ if (WIN32)
|
|||||||
if (BUILD_OPENMW)
|
if (BUILD_OPENMW)
|
||||||
# \bigobj is required:
|
# \bigobj is required:
|
||||||
# 1) for OPENMW_UNITY_BUILD;
|
# 1) for OPENMW_UNITY_BUILD;
|
||||||
# 2) to compile lua binginds, because sol3 is heavily templated.
|
# 2) to compile lua bindings, because sol3 is heavily templated.
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD} /bigobj")
|
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD} /bigobj")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
#include <components/detournavigator/navmeshtilescache.hpp>
|
#include <components/detournavigator/navmeshtilescache.hpp>
|
||||||
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <random>
|
#include <random>
|
||||||
@ -15,13 +16,12 @@ namespace
|
|||||||
osg::Vec3f mAgentHalfExtents;
|
osg::Vec3f mAgentHalfExtents;
|
||||||
TilePosition mTilePosition;
|
TilePosition mTilePosition;
|
||||||
RecastMesh mRecastMesh;
|
RecastMesh mRecastMesh;
|
||||||
std::vector<OffMeshConnection> mOffMeshConnections;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
Key mKey;
|
Key mKey;
|
||||||
NavMeshData mValue;
|
PreparedNavMeshData mValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Random>
|
template <typename Random>
|
||||||
@ -31,6 +31,14 @@ namespace
|
|||||||
return TilePosition(distribution(random), distribution(random));
|
return TilePosition(distribution(random), distribution(random));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Random>
|
||||||
|
TileBounds generateTileBounds(Random& random)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
|
const osg::Vec2f min(distribution(random), distribution(random));
|
||||||
|
return TileBounds {min, min + osg::Vec2f(1.0, 1.0)};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Random>
|
template <typename Random>
|
||||||
osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random)
|
osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random)
|
||||||
{
|
{
|
||||||
@ -81,22 +89,55 @@ namespace
|
|||||||
template <typename OutputIterator, typename Random>
|
template <typename OutputIterator, typename Random>
|
||||||
void generateWater(OutputIterator out, std::size_t count, Random& random)
|
void generateWater(OutputIterator out, std::size_t count, Random& random)
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<btScalar> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::generate_n(out, count, [&] {
|
std::generate_n(out, count, [&] {
|
||||||
const btVector3 shift(distribution(random), distribution(random), distribution(random));
|
const osg::Vec3f shift(distribution(random), distribution(random), distribution(random));
|
||||||
return RecastMesh::Water {1, btTransform(btMatrix3x3::getIdentity(), shift)};
|
return Cell {1, shift};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
template <class Random>
|
||||||
void generateOffMeshConnection(OutputIterator out, std::size_t count, Random& random)
|
Mesh generateMesh(std::size_t triangles, Random& random)
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<btScalar> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::generate_n(out, count, [&] {
|
std::vector<float> vertices;
|
||||||
const osg::Vec3f start(distribution(random), distribution(random), distribution(random));
|
std::vector<int> indices;
|
||||||
const osg::Vec3f end(distribution(random), distribution(random), distribution(random));
|
std::vector<AreaType> areaTypes;
|
||||||
return OffMeshConnection {start, end, generateAreaType(random)};
|
if (distribution(random) < 0.939)
|
||||||
|
{
|
||||||
|
generateVertices(std::back_inserter(vertices), triangles * 2.467, random);
|
||||||
|
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.279, random);
|
||||||
|
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
|
||||||
|
}
|
||||||
|
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Random>
|
||||||
|
Heightfield generateHeightfield(Random& random)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
|
Heightfield result;
|
||||||
|
result.mBounds = generateTileBounds(random);
|
||||||
|
result.mMinHeight = distribution(random);
|
||||||
|
result.mMaxHeight = result.mMinHeight + 1.0;
|
||||||
|
result.mShift = osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
||||||
|
result.mScale = distribution(random);
|
||||||
|
result.mLength = static_cast<std::uint8_t>(ESM::Land::LAND_SIZE);
|
||||||
|
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
||||||
|
{
|
||||||
|
return distribution(random);
|
||||||
});
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Random>
|
||||||
|
FlatHeightfield generateFlatHeightfield(Random& random)
|
||||||
|
{
|
||||||
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
|
FlatHeightfield result;
|
||||||
|
result.mBounds = generateTileBounds(random);
|
||||||
|
result.mHeight = distribution(random);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Random>
|
template <class Random>
|
||||||
@ -106,22 +147,15 @@ namespace
|
|||||||
const TilePosition tilePosition = generateTilePosition(10000, random);
|
const TilePosition tilePosition = generateTilePosition(10000, random);
|
||||||
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
||||||
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
||||||
std::vector<float> vertices;
|
Mesh mesh = generateMesh(triangles, random);
|
||||||
generateVertices(std::back_inserter(vertices), triangles * 1.98, random);
|
std::vector<Cell> water;
|
||||||
std::vector<int> indices;
|
generateWater(std::back_inserter(water), 1, random);
|
||||||
generateIndices(std::back_inserter(indices), static_cast<int>(vertices.size() / 3) - 1, vertices.size() * 1.53, random);
|
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
||||||
std::vector<AreaType> areaTypes;
|
{generateHeightfield(random)}, {generateFlatHeightfield(random)});
|
||||||
generateAreaTypes(std::back_inserter(areaTypes), indices.size() / 3, random);
|
return Key {agentHalfExtents, tilePosition, std::move(recastMesh)};
|
||||||
std::vector<RecastMesh::Water> water;
|
|
||||||
generateWater(std::back_inserter(water), 2, random);
|
|
||||||
RecastMesh recastMesh(generation, revision, std::move(indices), std::move(vertices),
|
|
||||||
std::move(areaTypes), std::move(water));
|
|
||||||
std::vector<OffMeshConnection> offMeshConnections;
|
|
||||||
generateOffMeshConnection(std::back_inserter(offMeshConnections), 300, random);
|
|
||||||
return Key {agentHalfExtents, tilePosition, std::move(recastMesh), std::move(offMeshConnections)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::size_t trianglesPerTile = 310;
|
constexpr std::size_t trianglesPerTile = 239;
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
template <typename OutputIterator, typename Random>
|
||||||
void generateKeys(OutputIterator out, std::size_t count, Random& random)
|
void generateKeys(OutputIterator out, std::size_t count, Random& random)
|
||||||
@ -137,7 +171,8 @@ namespace
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Key key = generateKey(trianglesPerTile, random);
|
Key key = generateKey(trianglesPerTile, random);
|
||||||
cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections, NavMeshData());
|
cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh,
|
||||||
|
std::make_unique<PreparedNavMeshData>());
|
||||||
*out++ = std::move(key);
|
*out++ = std::move(key);
|
||||||
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
||||||
if (size >= newSize)
|
if (size >= newSize)
|
||||||
@ -159,7 +194,7 @@ namespace
|
|||||||
while (state.KeepRunning())
|
while (state.KeepRunning())
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
const auto& key = keys[n++ % keys.size()];
|
||||||
const auto result = cache.get(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections);
|
const auto result = cache.get(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh);
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,7 +222,8 @@ namespace
|
|||||||
while (state.KeepRunning())
|
while (state.KeepRunning())
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
const auto& key = keys[n++ % keys.size()];
|
||||||
const auto result = cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh, key.mOffMeshConnections, NavMeshData());
|
const auto result = cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh,
|
||||||
|
std::make_unique<PreparedNavMeshData>());
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||||||
if(!quiet) std::cout << " References:\n";
|
if(!quiet) std::cout << " References:\n";
|
||||||
|
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
while(cell.getNextRef(esm, ref, deleted))
|
ESM::MovedCellRef movedCellRef;
|
||||||
|
bool moved = false;
|
||||||
|
while(cell.getNextRef(esm, ref, deleted, movedCellRef, moved))
|
||||||
{
|
{
|
||||||
if (save) {
|
if (save) {
|
||||||
info.data.mCellRefs[&cell].push_back(std::make_pair(ref, deleted));
|
info.data.mCellRefs[&cell].push_back(std::make_pair(ref, deleted));
|
||||||
@ -244,7 +246,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||||||
|
|
||||||
if(quiet) continue;
|
if(quiet) continue;
|
||||||
|
|
||||||
std::cout << " Refnum: " << ref.mRefNum.mIndex << '\n';
|
std::cout << " - Refnum: " << ref.mRefNum.mIndex << '\n';
|
||||||
std::cout << " ID: " << ref.mRefID << '\n';
|
std::cout << " ID: " << ref.mRefID << '\n';
|
||||||
std::cout << " Position: (" << ref.mPos.pos[0] << ", " << ref.mPos.pos[1] << ", " << ref.mPos.pos[2] << ")\n";
|
std::cout << " Position: (" << ref.mPos.pos[0] << ", " << ref.mPos.pos[1] << ", " << ref.mPos.pos[2] << ")\n";
|
||||||
if (ref.mScale != 1.f)
|
if (ref.mScale != 1.f)
|
||||||
@ -276,6 +278,13 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||||||
if (!ref.mDestCell.empty())
|
if (!ref.mDestCell.empty())
|
||||||
std::cout << " Destination cell: " << ref.mDestCell << '\n';
|
std::cout << " Destination cell: " << ref.mDestCell << '\n';
|
||||||
}
|
}
|
||||||
|
std::cout << " Moved: " << std::boolalpha << moved << std::noboolalpha << '\n';
|
||||||
|
if (moved)
|
||||||
|
{
|
||||||
|
std::cout << " Moved refnum: " << movedCellRef.mRefNum.mIndex << '\n';
|
||||||
|
std::cout << " Moved content file: " << movedCellRef.mRefNum.mContentFile << '\n';
|
||||||
|
std::cout << " Target: " << movedCellRef.mTarget[0] << ", " << movedCellRef.mTarget[1] << '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <climits> // INT_MIN
|
||||||
|
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
|
|
||||||
@ -357,7 +358,7 @@ namespace ESSImport
|
|||||||
|
|
||||||
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
std::string idLower = Misc::StringUtils::lowerCase(out.mRefID);
|
||||||
|
|
||||||
std::map<std::pair<int, std::string>, NPCC>::const_iterator npccIt = mContext->mNpcChanges.find(
|
auto npccIt = mContext->mNpcChanges.find(
|
||||||
std::make_pair(refIndex, out.mRefID));
|
std::make_pair(refIndex, out.mRefID));
|
||||||
if (npccIt != mContext->mNpcChanges.end())
|
if (npccIt != mContext->mNpcChanges.end())
|
||||||
{
|
{
|
||||||
@ -369,6 +370,8 @@ namespace ESSImport
|
|||||||
// from the ESM with default values
|
// from the ESM with default values
|
||||||
if (cellref.mHasACDT)
|
if (cellref.mHasACDT)
|
||||||
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||||
|
else
|
||||||
|
objstate.mCreatureStats.mGoldPool = INT_MIN; // HACK: indicates no ACDT
|
||||||
if (cellref.mHasACSC)
|
if (cellref.mHasACSC)
|
||||||
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||||
convertNpcData(cellref, objstate.mNpcStats);
|
convertNpcData(cellref, objstate.mNpcStats);
|
||||||
@ -383,7 +386,7 @@ namespace ESSImport
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::pair<int, std::string>, CNTC>::const_iterator cntcIt = mContext->mContainerChanges.find(
|
auto cntcIt = mContext->mContainerChanges.find(
|
||||||
std::make_pair(refIndex, out.mRefID));
|
std::make_pair(refIndex, out.mRefID));
|
||||||
if (cntcIt != mContext->mContainerChanges.end())
|
if (cntcIt != mContext->mContainerChanges.end())
|
||||||
{
|
{
|
||||||
@ -398,7 +401,7 @@ namespace ESSImport
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::pair<int, std::string>, CREC>::const_iterator crecIt = mContext->mCreatureChanges.find(
|
auto crecIt = mContext->mCreatureChanges.find(
|
||||||
std::make_pair(refIndex, out.mRefID));
|
std::make_pair(refIndex, out.mRefID));
|
||||||
if (crecIt != mContext->mCreatureChanges.end())
|
if (crecIt != mContext->mCreatureChanges.end())
|
||||||
{
|
{
|
||||||
@ -410,6 +413,8 @@ namespace ESSImport
|
|||||||
// from the ESM with default values
|
// from the ESM with default values
|
||||||
if (cellref.mHasACDT)
|
if (cellref.mHasACDT)
|
||||||
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
convertACDT(cellref.mACDT, objstate.mCreatureStats);
|
||||||
|
else
|
||||||
|
objstate.mCreatureStats.mGoldPool = INT_MIN; // HACK: indicates no ACDT
|
||||||
if (cellref.mHasACSC)
|
if (cellref.mHasACSC)
|
||||||
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
convertACSC(cellref.mACSC, objstate.mCreatureStats);
|
||||||
convertCREC(crecIt->second, objstate);
|
convertCREC(crecIt->second, objstate);
|
||||||
|
@ -124,11 +124,9 @@ public:
|
|||||||
{
|
{
|
||||||
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt.mLevel;
|
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt.mLevel;
|
||||||
mContext->mPlayerBase = npc;
|
mContext->mPlayerBase = npc;
|
||||||
ESM::SpellState::SpellParams empty;
|
|
||||||
// FIXME: player start spells and birthsign spells aren't listed here,
|
// FIXME: player start spells and birthsign spells aren't listed here,
|
||||||
// need to fix openmw to account for this
|
// need to fix openmw to account for this
|
||||||
for (const auto & spell : npc.mSpells.mList)
|
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells = npc.mSpells.mList;
|
||||||
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[spell] = empty;
|
|
||||||
|
|
||||||
// Clear the list now that we've written it, this prevents issues cropping up with
|
// Clear the list now that we've written it, this prevents issues cropping up with
|
||||||
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
|
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
|
||||||
@ -374,7 +372,7 @@ public:
|
|||||||
void write(ESM::ESMWriter &esm) override
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_DCOU);
|
esm.startRecord(ESM::REC_DCOU);
|
||||||
for (std::map<std::string, int>::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
|
for (auto it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
|
||||||
{
|
{
|
||||||
esm.writeHNString("ID__", it->first);
|
esm.writeHNString("ID__", it->first);
|
||||||
esm.writeHNT ("COUN", it->second);
|
esm.writeHNT ("COUN", it->second);
|
||||||
@ -397,7 +395,7 @@ public:
|
|||||||
faction.load(esm, isDeleted);
|
faction.load(esm, isDeleted);
|
||||||
std::string id = Misc::StringUtils::lowerCase(faction.mId);
|
std::string id = Misc::StringUtils::lowerCase(faction.mId);
|
||||||
|
|
||||||
for (std::map<std::string, int>::const_iterator it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it)
|
for (auto it = faction.mReactions.begin(); it != faction.mReactions.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string faction2 = Misc::StringUtils::lowerCase(it->first);
|
std::string faction2 = Misc::StringUtils::lowerCase(it->first);
|
||||||
mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second));
|
mContext->mDialogueState.mChangedFactionReaction[id].insert(std::make_pair(faction2, it->second));
|
||||||
@ -431,7 +429,7 @@ public:
|
|||||||
void write(ESM::ESMWriter &esm) override
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
ESM::StolenItems items;
|
ESM::StolenItems items;
|
||||||
for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
for (auto it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
||||||
{
|
{
|
||||||
std::map<std::pair<std::string, bool>, int> owners;
|
std::map<std::pair<std::string, bool>, int> owners;
|
||||||
for (const auto & ownerIt : it->second)
|
for (const auto & ownerIt : it->second)
|
||||||
@ -487,7 +485,7 @@ public:
|
|||||||
}
|
}
|
||||||
void write(ESM::ESMWriter &esm) override
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
for (std::map<std::string, DIAL>::const_iterator it = mDials.begin(); it != mDials.end(); ++it)
|
for (auto it = mDials.begin(); it != mDials.end(); ++it)
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_QUES);
|
esm.startRecord(ESM::REC_QUES);
|
||||||
ESM::QuestState state;
|
ESM::QuestState state;
|
||||||
|
@ -385,7 +385,7 @@ namespace ESSImport
|
|||||||
|
|
||||||
// Writing order should be Dynamic Store -> Cells -> Player,
|
// Writing order should be Dynamic Store -> Cells -> Player,
|
||||||
// so that references to dynamic records can be recognized when loading
|
// so that references to dynamic records can be recognized when loading
|
||||||
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
for (auto it = converters.begin();
|
||||||
it != converters.end(); ++it)
|
it != converters.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->second->getStage() != 0)
|
if (it->second->getStage() != 0)
|
||||||
@ -398,7 +398,7 @@ namespace ESSImport
|
|||||||
context.mPlayerBase.save(writer);
|
context.mPlayerBase.save(writer);
|
||||||
writer.endRecord(ESM::REC_NPC_);
|
writer.endRecord(ESM::REC_NPC_);
|
||||||
|
|
||||||
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
for (auto it = converters.begin();
|
||||||
it != converters.end(); ++it)
|
it != converters.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->second->getStage() != 1)
|
if (it->second->getStage() != 1)
|
||||||
@ -423,7 +423,7 @@ namespace ESSImport
|
|||||||
writer.endRecord(ESM::REC_ACTC);
|
writer.endRecord(ESM::REC_ACTC);
|
||||||
|
|
||||||
// Stage 2 requires cell references to be written / actors IDs assigned
|
// Stage 2 requires cell references to be written / actors IDs assigned
|
||||||
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
for (auto it = converters.begin();
|
||||||
it != converters.end(); ++it)
|
it != converters.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->second->getStage() != 2)
|
if (it->second->getStage() != 2)
|
||||||
|
@ -36,23 +36,6 @@ set(LAUNCHER_HEADER
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Headers that must be pre-processed
|
# Headers that must be pre-processed
|
||||||
set(LAUNCHER_HEADER_MOC
|
|
||||||
datafilespage.hpp
|
|
||||||
graphicspage.hpp
|
|
||||||
maindialog.hpp
|
|
||||||
playpage.hpp
|
|
||||||
textslotmsgbox.hpp
|
|
||||||
settingspage.hpp
|
|
||||||
advancedpage.hpp
|
|
||||||
|
|
||||||
utils/cellnameloader.hpp
|
|
||||||
utils/textinputdialog.hpp
|
|
||||||
utils/profilescombobox.hpp
|
|
||||||
utils/lineedit.hpp
|
|
||||||
utils/openalutil.hpp
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
set(LAUNCHER_UI
|
set(LAUNCHER_UI
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
||||||
@ -74,7 +57,6 @@ if(WIN32)
|
|||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
|
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
|
||||||
QT5_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
|
||||||
QT5_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
|
QT5_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
@ -99,7 +81,7 @@ endif (WIN32)
|
|||||||
target_link_libraries(openmw-launcher
|
target_link_libraries(openmw-launcher
|
||||||
${SDL2_LIBRARY_ONLY}
|
${SDL2_LIBRARY_ONLY}
|
||||||
${OPENAL_LIBRARY}
|
${OPENAL_LIBRARY}
|
||||||
components
|
components_qt
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(openmw-launcher Qt5::Widgets Qt5::Core)
|
target_link_libraries(openmw-launcher Qt5::Widgets Qt5::Core)
|
||||||
@ -109,4 +91,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
|||||||
target_link_libraries(openmw-launcher gcov)
|
target_link_libraries(openmw-launcher gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(USE_QT)
|
||||||
|
set_property(TARGET openmw-launcher PROPERTY AUTOMOC ON)
|
||||||
|
endif(USE_QT)
|
||||||
|
|
||||||
|
@ -192,6 +192,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
|||||||
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
|
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
|
||||||
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
|
||||||
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
loadSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
|
loadSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||||
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
loadSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
|
scalingSpinBox->setValue(Settings::Manager::getFloat("scaling factor", "GUI"));
|
||||||
}
|
}
|
||||||
@ -352,6 +353,7 @@ void Launcher::AdvancedPage::saveSettings()
|
|||||||
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
||||||
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
||||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
|
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
float uiScalingFactor = scalingSpinBox->value();
|
float uiScalingFactor = scalingSpinBox->value();
|
||||||
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))
|
if (uiScalingFactor != Settings::Manager::getFloat("scaling factor", "GUI"))
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#include <components/config/gamesettings.hpp>
|
#include <components/config/gamesettings.hpp>
|
||||||
#include <components/config/launchersettings.hpp>
|
#include <components/config/launchersettings.hpp>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "utils/textinputdialog.hpp"
|
#include "utils/textinputdialog.hpp"
|
||||||
#include "utils/profilescombobox.hpp"
|
#include "utils/profilescombobox.hpp"
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <array>
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
|
|
||||||
QString getAspect(int x, int y)
|
QString getAspect(int x, int y)
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QInputDialog>
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
@ -52,8 +51,8 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
|||||||
iconWidget->setCurrentRow(0);
|
iconWidget->setCurrentRow(0);
|
||||||
iconWidget->setFlow(QListView::LeftToRight);
|
iconWidget->setFlow(QListView::LeftToRight);
|
||||||
|
|
||||||
QPushButton *helpButton = new QPushButton(tr("Help"));
|
auto *helpButton = new QPushButton(tr("Help"));
|
||||||
QPushButton *playButton = new QPushButton(tr("Play"));
|
auto *playButton = new QPushButton(tr("Play"));
|
||||||
buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
|
buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
|
||||||
buttonBox->addButton(helpButton, QDialogButtonBox::HelpRole);
|
buttonBox->addButton(helpButton, QDialogButtonBox::HelpRole);
|
||||||
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
|
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
|
||||||
@ -79,31 +78,31 @@ void Launcher::MainDialog::createIcons()
|
|||||||
if (!QIcon::hasThemeIcon("document-new"))
|
if (!QIcon::hasThemeIcon("document-new"))
|
||||||
QIcon::setThemeName("tango");
|
QIcon::setThemeName("tango");
|
||||||
|
|
||||||
QListWidgetItem *playButton = new QListWidgetItem(iconWidget);
|
auto *playButton = new QListWidgetItem(iconWidget);
|
||||||
playButton->setIcon(QIcon(":/images/openmw.png"));
|
playButton->setIcon(QIcon(":/images/openmw.png"));
|
||||||
playButton->setText(tr("Play"));
|
playButton->setText(tr("Play"));
|
||||||
playButton->setTextAlignment(Qt::AlignCenter);
|
playButton->setTextAlignment(Qt::AlignCenter);
|
||||||
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget);
|
auto *dataFilesButton = new QListWidgetItem(iconWidget);
|
||||||
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
|
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
|
||||||
dataFilesButton->setText(tr("Data Files"));
|
dataFilesButton->setText(tr("Data Files"));
|
||||||
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
|
auto *graphicsButton = new QListWidgetItem(iconWidget);
|
||||||
graphicsButton->setIcon(QIcon(":/images/preferences-video.png"));
|
graphicsButton->setIcon(QIcon(":/images/preferences-video.png"));
|
||||||
graphicsButton->setText(tr("Graphics"));
|
graphicsButton->setText(tr("Graphics"));
|
||||||
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
|
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
|
||||||
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
QListWidgetItem *settingsButton = new QListWidgetItem(iconWidget);
|
auto *settingsButton = new QListWidgetItem(iconWidget);
|
||||||
settingsButton->setIcon(QIcon(":/images/preferences.png"));
|
settingsButton->setIcon(QIcon(":/images/preferences.png"));
|
||||||
settingsButton->setText(tr("Settings"));
|
settingsButton->setText(tr("Settings"));
|
||||||
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
settingsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
settingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||||
|
|
||||||
QListWidgetItem *advancedButton = new QListWidgetItem(iconWidget);
|
auto *advancedButton = new QListWidgetItem(iconWidget);
|
||||||
advancedButton->setIcon(QIcon(":/images/preferences-advanced.png"));
|
advancedButton->setIcon(QIcon(":/images/preferences-advanced.png"));
|
||||||
advancedButton->setText(tr("Advanced"));
|
advancedButton->setText(tr("Advanced"));
|
||||||
advancedButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
advancedButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
|
@ -4,11 +4,6 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
|
|
||||||
#include <components/config/gamesettings.hpp>
|
|
||||||
#include <components/config/launchersettings.hpp>
|
|
||||||
|
|
||||||
#include "utils/textinputdialog.hpp"
|
#include "utils/textinputdialog.hpp"
|
||||||
#include "datafilespage.hpp"
|
#include "datafilespage.hpp"
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <apps/openmw/mwsound/alext.h>
|
#include <apps/openmw/mwsound/alext.h>
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
|||||||
setEditable(true);
|
setEditable(true);
|
||||||
setValidator(mValidator);
|
setValidator(mValidator);
|
||||||
|
|
||||||
ComboBoxLineEdit *edit = new ComboBoxLineEdit(this);
|
auto *edit = new ComboBoxLineEdit(this);
|
||||||
|
|
||||||
setLineEdit(edit);
|
setLineEdit(edit);
|
||||||
setCompleter(nullptr);
|
setCompleter(nullptr);
|
||||||
|
@ -16,7 +16,7 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
|
|||||||
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
||||||
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
|
mButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
|
||||||
|
|
||||||
QLabel *label = new QLabel(this);
|
auto *label = new QLabel(this);
|
||||||
label->setText(text);
|
label->setText(text);
|
||||||
|
|
||||||
// Line edit
|
// Line edit
|
||||||
@ -25,7 +25,7 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString &
|
|||||||
mLineEdit->setValidator(validator);
|
mLineEdit->setValidator(validator);
|
||||||
mLineEdit->setCompleter(nullptr);
|
mLineEdit->setCompleter(nullptr);
|
||||||
|
|
||||||
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
|
auto *dialogLayout = new QVBoxLayout(this);
|
||||||
dialogLayout->addWidget(label);
|
dialogLayout->addWidget(label);
|
||||||
dialogLayout->addWidget(mLineEdit);
|
dialogLayout->addWidget(mLineEdit);
|
||||||
dialogLayout->addWidget(mButtonBox);
|
dialogLayout->addWidget(mButtonBox);
|
||||||
|
@ -778,7 +778,7 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, const multistrmap &ini) cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MwIniImporter::insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value) {
|
void MwIniImporter::insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value) {
|
||||||
const multistrmap::const_iterator it = cfg.find(key);
|
const auto it = cfg.find(key);
|
||||||
if(it == cfg.end()) {
|
if(it == cfg.end()) {
|
||||||
cfg.insert(std::make_pair (key, std::vector<std::string>() ));
|
cfg.insert(std::make_pair (key, std::vector<std::string>() ));
|
||||||
}
|
}
|
||||||
@ -791,7 +791,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
|
|||||||
std::string archive;
|
std::string archive;
|
||||||
|
|
||||||
// Search archives listed in ini file
|
// Search archives listed in ini file
|
||||||
multistrmap::const_iterator it = ini.begin();
|
auto it = ini.begin();
|
||||||
for(int i=0; it != ini.end(); i++) {
|
for(int i=0; it != ini.end(); i++) {
|
||||||
archive = baseArchive;
|
archive = baseArchive;
|
||||||
archive.append(std::to_string(i));
|
archive.append(std::to_string(i));
|
||||||
@ -813,7 +813,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
|
|||||||
// does not appears in the ini file
|
// does not appears in the ini file
|
||||||
cfg["fallback-archive"].push_back("Morrowind.bsa");
|
cfg["fallback-archive"].push_back("Morrowind.bsa");
|
||||||
|
|
||||||
for(std::vector<std::string>::const_iterator iter=archives.begin(); iter!=archives.end(); ++iter) {
|
for(auto iter=archives.begin(); iter!=archives.end(); ++iter) {
|
||||||
cfg["fallback-archive"].push_back(*iter);
|
cfg["fallback-archive"].push_back(*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,7 +886,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
|||||||
|
|
||||||
dataPaths.push_back(iniFilename.parent_path() /= "Data Files");
|
dataPaths.push_back(iniFilename.parent_path() /= "Data Files");
|
||||||
|
|
||||||
multistrmap::const_iterator it = ini.begin();
|
auto it = ini.begin();
|
||||||
for (int i=0; it != ini.end(); i++)
|
for (int i=0; it != ini.end(); i++)
|
||||||
{
|
{
|
||||||
std::string gameFile = baseGameFile;
|
std::string gameFile = baseGameFile;
|
||||||
@ -969,7 +969,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
|||||||
void MwIniImporter::writeToFile(std::ostream &out, const multistrmap &cfg) {
|
void MwIniImporter::writeToFile(std::ostream &out, const multistrmap &cfg) {
|
||||||
|
|
||||||
for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) {
|
for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) {
|
||||||
for(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {
|
for(auto entry=it->second.begin(); entry != it->second.end(); ++entry) {
|
||||||
out << (it->first) << "=" << (*entry) << std::endl;
|
out << (it->first) << "=" << (*entry) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,8 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "")
|
|||||||
myManager.addArchive(anArchive);
|
myManager.addArchive(anArchive);
|
||||||
myManager.buildIndex();
|
myManager.buildIndex();
|
||||||
|
|
||||||
std::map<std::string, VFS::File*> files=myManager.getIndex();
|
for(const auto& name : myManager.getRecursiveDirectoryIterator(""))
|
||||||
for(std::map<std::string, VFS::File*>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
|
||||||
{
|
{
|
||||||
std::string name = it->first;
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(isNIF(name))
|
if(isNIF(name))
|
||||||
{
|
{
|
||||||
@ -134,7 +131,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
Nif::NIFFile::setLoadUnsupportedFiles(true);
|
Nif::NIFFile::setLoadUnsupportedFiles(true);
|
||||||
// std::cout << "Reading Files" << std::endl;
|
// std::cout << "Reading Files" << std::endl;
|
||||||
for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
for(auto it=files.begin(); it!=files.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string name = *it;
|
std::string name = *it;
|
||||||
|
|
||||||
|
@ -8,29 +8,29 @@ opencs_units (model/doc
|
|||||||
document operation saving documentmanager loader runner operationholder
|
document operation saving documentmanager loader runner operationholder
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/doc
|
opencs_units (model/doc
|
||||||
stage savingstate savingstages blacklist messages
|
stage savingstate savingstages blacklist messages
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/doc
|
opencs_hdrs (model/doc
|
||||||
state
|
state
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units (model/world
|
opencs_units (model/world
|
||||||
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel
|
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel landtexturetableproxymodel
|
||||||
actoradapter
|
actoradapter idcollection
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units_noqt (model/world
|
opencs_units (model/world
|
||||||
universalid record commands columnbase columnimp scriptcontext cell refidcollection
|
universalid record commands columnbase columnimp scriptcontext cell refidcollection
|
||||||
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
|
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
|
||||||
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
|
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
|
||||||
idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro
|
idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/world
|
opencs_hdrs (model/world
|
||||||
columnimp idcollection collection info subcellcollection
|
columnimp idcollection collection info subcellcollection
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,14 +39,14 @@ opencs_units (model/tools
|
|||||||
tools reportmodel mergeoperation
|
tools reportmodel mergeoperation
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/tools
|
opencs_units (model/tools
|
||||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||||
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
||||||
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
|
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
|
||||||
mergestages gmstcheck topicinfocheck journalcheck enchantmentcheck
|
mergestages gmstcheck topicinfocheck journalcheck enchantmentcheck
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (model/tools
|
opencs_hdrs (model/tools
|
||||||
mergestate
|
mergestate
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,11 +57,11 @@ opencs_units (view/doc
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
opencs_units_noqt (view/doc
|
opencs_units (view/doc
|
||||||
subviewfactory
|
subviewfactory
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (view/doc
|
opencs_hdrs (view/doc
|
||||||
subviewfactoryimp
|
subviewfactoryimp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,10 +71,10 @@ opencs_units (view/world
|
|||||||
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||||
bodypartcreator landtexturecreator landcreator
|
bodypartcreator landtexturecreator landcreator tableheadermouseeventhandler
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units (view/world
|
||||||
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
|
||||||
scripthighlighter idvalidator dialoguecreator idcompletiondelegate
|
scripthighlighter idvalidator dialoguecreator idcompletiondelegate
|
||||||
colordelegate dragdroputils
|
colordelegate dragdroputils
|
||||||
@ -92,12 +92,12 @@ opencs_units (view/render
|
|||||||
cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands
|
cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/render
|
opencs_units (view/render
|
||||||
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
||||||
cellarrow cellmarker cellborder pathgrid
|
cellarrow cellmarker cellborder pathgrid
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_hdrs_noqt (view/render
|
opencs_hdrs (view/render
|
||||||
mask
|
mask
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ opencs_units (view/tools
|
|||||||
reportsubview reporttable searchsubview searchbox merge
|
reportsubview reporttable searchsubview searchbox merge
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/tools
|
opencs_units (view/tools
|
||||||
subviews
|
subviews
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -119,11 +119,11 @@ opencs_units (model/prefs
|
|||||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting
|
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/prefs
|
opencs_units (model/prefs
|
||||||
category
|
category
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (model/filter
|
opencs_units (model/filter
|
||||||
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
|
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -150,7 +150,6 @@ if(WIN32)
|
|||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
|
qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
|
||||||
qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
|
|
||||||
qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
|
qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
|
||||||
|
|
||||||
# for compiled .ui files
|
# for compiled .ui files
|
||||||
@ -229,34 +228,9 @@ target_link_libraries(openmw-cs
|
|||||||
${Boost_SYSTEM_LIBRARY}
|
${Boost_SYSTEM_LIBRARY}
|
||||||
${Boost_FILESYSTEM_LIBRARY}
|
${Boost_FILESYSTEM_LIBRARY}
|
||||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||||
components
|
components_qt
|
||||||
)
|
)
|
||||||
|
|
||||||
if(OSG_STATIC)
|
|
||||||
unset(_osg_plugins_static_files)
|
|
||||||
add_library(openmw_cs_osg_plugins INTERFACE)
|
|
||||||
foreach(_plugin ${USED_OSG_PLUGINS})
|
|
||||||
string(TOUPPER ${_plugin} _plugin_uc)
|
|
||||||
if(OPENMW_USE_SYSTEM_OSG)
|
|
||||||
list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY})
|
|
||||||
else()
|
|
||||||
list(APPEND _osg_plugins_static_files $<TARGET_FILE:${${_plugin_uc}_LIBRARY}>)
|
|
||||||
target_link_libraries(openmw_cs_osg_plugins INTERFACE $<TARGET_PROPERTY:${${_plugin_uc}_LIBRARY},LINK_LIBRARIES>)
|
|
||||||
add_dependencies(openmw_cs_osg_plugins ${${_plugin_uc}_LIBRARY})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
# We use --whole-archive because OSG plugins use registration.
|
|
||||||
get_whole_archive_options(_opts ${_osg_plugins_static_files})
|
|
||||||
target_link_options(openmw_cs_osg_plugins INTERFACE ${_opts})
|
|
||||||
target_link_libraries(openmw-cs openmw_cs_osg_plugins)
|
|
||||||
|
|
||||||
if(OPENMW_USE_SYSTEM_OSG)
|
|
||||||
# OSG plugin pkgconfig files are missing these dependencies.
|
|
||||||
# https://github.com/openscenegraph/OpenSceneGraph/issues/1052
|
|
||||||
target_link_libraries(openmw freetype jpeg png)
|
|
||||||
endif()
|
|
||||||
endif(OSG_STATIC)
|
|
||||||
|
|
||||||
target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL)
|
target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@ -284,3 +258,7 @@ endif (MSVC)
|
|||||||
if(APPLE)
|
if(APPLE)
|
||||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT Bundle)
|
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT Bundle)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(USE_QT)
|
||||||
|
set_property(TARGET openmw-cs PROPERTY AUTOMOC ON)
|
||||||
|
endif(USE_QT)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "document.hpp"
|
#include "document.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
@ -115,10 +116,10 @@ void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
|
|||||||
{
|
{
|
||||||
if (getData().getGmsts().searchId (gmst.mId)==-1)
|
if (getData().getGmsts().searchId (gmst.mId)==-1)
|
||||||
{
|
{
|
||||||
CSMWorld::Record<ESM::GameSetting> record;
|
std::unique_ptr<CSMWorld::Record<ESM::GameSetting> > record(new CSMWorld::Record<ESM::GameSetting>);
|
||||||
record.mBase = gmst;
|
record->mBase = gmst;
|
||||||
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
getData().getGmsts().appendRecord (record);
|
getData().getGmsts().appendRecord (std::move(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,10 +127,10 @@ void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global)
|
|||||||
{
|
{
|
||||||
if (getData().getGlobals().searchId (global.mId)==-1)
|
if (getData().getGlobals().searchId (global.mId)==-1)
|
||||||
{
|
{
|
||||||
CSMWorld::Record<ESM::Global> record;
|
std::unique_ptr<CSMWorld::Record<ESM::Global> > record(new CSMWorld::Record<ESM::Global>);
|
||||||
record.mBase = global;
|
record->mBase = global;
|
||||||
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
getData().getGlobals().appendRecord (record);
|
getData().getGlobals().appendRecord (std::move(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,10 +138,10 @@ void CSMDoc::Document::addOptionalMagicEffect (const ESM::MagicEffect& magicEffe
|
|||||||
{
|
{
|
||||||
if (getData().getMagicEffects().searchId (magicEffect.mId)==-1)
|
if (getData().getMagicEffects().searchId (magicEffect.mId)==-1)
|
||||||
{
|
{
|
||||||
CSMWorld::Record<ESM::MagicEffect> record;
|
std::unique_ptr<CSMWorld::Record<ESM::MagicEffect> > record(new CSMWorld::Record<ESM::MagicEffect>);
|
||||||
record.mBase = magicEffect;
|
record->mBase = magicEffect;
|
||||||
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
getData().getMagicEffects().appendRecord (record);
|
getData().getMagicEffects().appendRecord (std::move(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,19 +85,19 @@ void CSMDoc::Loader::load()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter->second.mFile<size)
|
if (iter->second.mFile<size) // start loading the files
|
||||||
{
|
{
|
||||||
boost::filesystem::path path = document->getContentFiles()[iter->second.mFile];
|
boost::filesystem::path path = document->getContentFiles()[iter->second.mFile];
|
||||||
|
|
||||||
int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, false);
|
int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, /*project*/false);
|
||||||
iter->second.mRecordsLeft = true;
|
iter->second.mRecordsLeft = true;
|
||||||
iter->second.mRecordsLoaded = 0;
|
iter->second.mRecordsLoaded = 0;
|
||||||
|
|
||||||
emit nextStage (document, path.filename().string(), steps);
|
emit nextStage (document, path.filename().string(), steps);
|
||||||
}
|
}
|
||||||
else if (iter->second.mFile==size)
|
else if (iter->second.mFile==size) // start loading the last (project) file
|
||||||
{
|
{
|
||||||
int steps = document->getData().startLoading (document->getProjectPath(), false, true);
|
int steps = document->getData().startLoading (document->getProjectPath(), /*base*/false, true);
|
||||||
iter->second.mRecordsLeft = true;
|
iter->second.mRecordsLeft = true;
|
||||||
iter->second.mRecordsLoaded = 0;
|
iter->second.mRecordsLoaded = 0;
|
||||||
|
|
||||||
|
@ -83,6 +83,8 @@ void CSMDoc::Runner::start (bool delayed)
|
|||||||
arguments <<
|
arguments <<
|
||||||
QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str());
|
QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str());
|
||||||
|
|
||||||
|
arguments << "--replace=content";
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
|
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
|
||||||
iter!=mContentFiles.end(); ++iter)
|
iter!=mContentFiles.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +114,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message
|
|||||||
|
|
||||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
||||||
{
|
{
|
||||||
if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted)
|
if ((*iter)->isModified() || (*iter)->mState == CSMWorld::RecordBase::State_Deleted)
|
||||||
{
|
{
|
||||||
infoModified = true;
|
infoModified = true;
|
||||||
break;
|
break;
|
||||||
@ -140,9 +140,9 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message
|
|||||||
// write modified selected info records
|
// write modified selected info records
|
||||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
||||||
{
|
{
|
||||||
if (iter->isModified() || iter->mState == CSMWorld::RecordBase::State_Deleted)
|
if ((*iter)->isModified() || (*iter)->mState == CSMWorld::RecordBase::State_Deleted)
|
||||||
{
|
{
|
||||||
ESM::DialInfo info = iter->get();
|
ESM::DialInfo info = (*iter)->get();
|
||||||
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
|
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
|
||||||
|
|
||||||
info.mPrev = "";
|
info.mPrev = "";
|
||||||
@ -151,7 +151,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message
|
|||||||
CSMWorld::InfoCollection::RecordConstIterator prev = iter;
|
CSMWorld::InfoCollection::RecordConstIterator prev = iter;
|
||||||
--prev;
|
--prev;
|
||||||
|
|
||||||
info.mPrev = prev->get().mId.substr (prev->get().mId.find_last_of ('#')+1);
|
info.mPrev = (*prev)->get().mId.substr ((*prev)->get().mId.find_last_of ('#')+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::InfoCollection::RecordConstIterator next = iter;
|
CSMWorld::InfoCollection::RecordConstIterator next = iter;
|
||||||
@ -160,11 +160,11 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message
|
|||||||
info.mNext = "";
|
info.mNext = "";
|
||||||
if (next!=range.second)
|
if (next!=range.second)
|
||||||
{
|
{
|
||||||
info.mNext = next->get().mId.substr (next->get().mId.find_last_of ('#')+1);
|
info.mNext = (*next)->get().mId.substr ((*next)->get().mId.find_last_of ('#')+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.startRecord (info.sRecordId);
|
writer.startRecord (info.sRecordId);
|
||||||
info.save (writer, iter->mState == CSMWorld::RecordBase::State_Deleted);
|
info.save (writer, (*iter)->mState == CSMWorld::RecordBase::State_Deleted);
|
||||||
writer.endRecord (info.sRecordId);
|
writer.endRecord (info.sRecordId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ namespace CSMDoc
|
|||||||
state == CSMWorld::RecordBase::State_ModifiedOnly ||
|
state == CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||||
state == CSMWorld::RecordBase::State_Deleted)
|
state == CSMWorld::RecordBase::State_Deleted)
|
||||||
{
|
{
|
||||||
writer.startRecord (record.sRecordId);
|
writer.startRecord (record.sRecordId, record.mRecordFlags);
|
||||||
record.save (writer, state == CSMWorld::RecordBase::State_Deleted);
|
record.save (writer, state == CSMWorld::RecordBase::State_Deleted);
|
||||||
writer.endRecord (record.sRecordId);
|
writer.endRecord (record.sRecordId);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages)
|
|||||||
|
|
||||||
for (CSMWorld::InfoCollection::RecordConstIterator it = range.first; it != range.second; ++it)
|
for (CSMWorld::InfoCollection::RecordConstIterator it = range.first; it != range.second; ++it)
|
||||||
{
|
{
|
||||||
const CSMWorld::Record<CSMWorld::Info> infoRecord = (*it);
|
const CSMWorld::Record<CSMWorld::Info> infoRecord = (*it->get());
|
||||||
|
|
||||||
if (infoRecord.isDeleted())
|
if (infoRecord.isDeleted())
|
||||||
continue;
|
continue;
|
||||||
|
@ -103,10 +103,9 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa
|
|||||||
ref.mRefNum.mContentFile = 0;
|
ref.mRefNum.mContentFile = 0;
|
||||||
ref.mNew = false;
|
ref.mNew = false;
|
||||||
|
|
||||||
CSMWorld::Record<CSMWorld::CellRef> newRecord (
|
mState.mTarget->getData().getReferences().appendRecord (
|
||||||
CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &ref);
|
std::make_unique<CSMWorld::Record<CSMWorld::CellRef> >(
|
||||||
|
CSMWorld::Record<CSMWorld::CellRef>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &ref)));
|
||||||
mState.mTarget->getData().getReferences().appendRecord (newRecord);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +127,9 @@ void CSMTools::PopulateLandTexturesMergeStage::perform (int stage, CSMDoc::Messa
|
|||||||
|
|
||||||
if (!record.isDeleted())
|
if (!record.isDeleted())
|
||||||
{
|
{
|
||||||
mState.mTarget->getData().getLandTextures().appendRecord(record);
|
mState.mTarget->getData().getLandTextures().appendRecord(
|
||||||
|
std::make_unique<CSMWorld::Record<CSMWorld::LandTexture> >(
|
||||||
|
CSMWorld::Record<CSMWorld::LandTexture>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +151,9 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
|
|||||||
|
|
||||||
if (!record.isDeleted())
|
if (!record.isDeleted())
|
||||||
{
|
{
|
||||||
mState.mTarget->getData().getLand().appendRecord (record);
|
mState.mTarget->getData().getLand().appendRecord (
|
||||||
|
std::make_unique<CSMWorld::Record<CSMWorld::Land> >(
|
||||||
|
CSMWorld::Record<CSMWorld::Land>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,10 +188,9 @@ void CSMTools::FixLandsAndLandTexturesMergeStage::perform (int stage, CSMDoc::Me
|
|||||||
const CSMWorld::Record<CSMWorld::Land>& oldRecord =
|
const CSMWorld::Record<CSMWorld::Land>& oldRecord =
|
||||||
mState.mTarget->getData().getLand().getRecord (stage);
|
mState.mTarget->getData().getLand().getRecord (stage);
|
||||||
|
|
||||||
CSMWorld::Record<CSMWorld::Land> newRecord(CSMWorld::RecordBase::State_ModifiedOnly,
|
mState.mTarget->getData().getLand().setRecord (stage,
|
||||||
nullptr, &oldRecord.get());
|
std::make_unique<CSMWorld::Record<CSMWorld::Land> >(
|
||||||
|
CSMWorld::Record<CSMWorld::Land>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &oldRecord.get())));
|
||||||
mState.mTarget->getData().getLand().setRecord(stage, newRecord);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
@ -82,7 +83,8 @@ namespace CSMTools
|
|||||||
const CSMWorld::Record<RecordType>& record = source.getRecord (stage);
|
const CSMWorld::Record<RecordType>& record = source.getRecord (stage);
|
||||||
|
|
||||||
if (!record.isDeleted())
|
if (!record.isDeleted())
|
||||||
target.appendRecord (CSMWorld::Record<RecordType> (CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get()));
|
target.appendRecord (std::make_unique<CSMWorld::Record<RecordType> >(
|
||||||
|
CSMWorld::Record<RecordType>(CSMWorld::RecordBase::State_ModifiedOnly, nullptr, &record.get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
class MergeRefIdsStage : public CSMDoc::Stage
|
class MergeRefIdsStage : public CSMDoc::Stage
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
#include "data.hpp"
|
#include "data.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
const std::string& ActorAdapter::RaceData::getId() const
|
const std::string& ActorAdapter::RaceData::getId() const
|
||||||
@ -121,7 +124,7 @@ namespace CSMWorld
|
|||||||
return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf);
|
return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
std::string_view ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
||||||
{
|
{
|
||||||
auto it = mParts.find(index);
|
auto it = mParts.find(index);
|
||||||
if (it == mParts.end())
|
if (it == mParts.end())
|
||||||
@ -131,7 +134,7 @@ namespace CSMWorld
|
|||||||
if (mFemale)
|
if (mFemale)
|
||||||
{
|
{
|
||||||
// Note: we should use male parts for females as fallback
|
// Note: we should use male parts for females as fallback
|
||||||
const std::string femalePart = mRaceData->getFemalePart(index);
|
const std::string& femalePart = mRaceData->getFemalePart(index);
|
||||||
if (!femalePart.empty())
|
if (!femalePart.empty())
|
||||||
return femalePart;
|
return femalePart;
|
||||||
}
|
}
|
||||||
@ -139,11 +142,10 @@ namespace CSMWorld
|
|||||||
return mRaceData->getMalePart(index);
|
return mRaceData->getMalePart(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& partName = it->second.first;
|
return it->second.first;
|
||||||
return partName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActorAdapter::ActorData::hasDependency(const std::string& id) const
|
bool ActorAdapter::ActorData::hasDependency(const std::string& id) const
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
@ -93,7 +95,7 @@ namespace CSMWorld
|
|||||||
/// Returns the skeleton the actor should use for attaching parts to
|
/// Returns the skeleton the actor should use for attaching parts to
|
||||||
std::string getSkeleton() const;
|
std::string getSkeleton() const;
|
||||||
/// Retrieves the associated actor part
|
/// Retrieves the associated actor part
|
||||||
const std::string getPart(ESM::PartReferenceType index) const;
|
std::string_view getPart(ESM::PartReferenceType index) const;
|
||||||
/// Checks if the actor has a data dependency
|
/// Checks if the actor has a data dependency
|
||||||
bool hasDependency(const std::string& id) const;
|
bool hasDependency(const std::string& id) const;
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
@ -84,7 +86,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::vector<Record<ESXRecordT> > mRecords;
|
std::vector<std::unique_ptr<Record<ESXRecordT> > > mRecords;
|
||||||
std::map<std::string, int> mIndex;
|
std::map<std::string, int> mIndex;
|
||||||
std::vector<Column<ESXRecordT> *> mColumns;
|
std::vector<Column<ESXRecordT> *> mColumns;
|
||||||
|
|
||||||
@ -94,9 +96,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
const std::map<std::string, int>& getIdMap() const;
|
const std::vector<std::unique_ptr<Record<ESXRecordT> > >& getRecords() const;
|
||||||
|
|
||||||
const std::vector<Record<ESXRecordT> >& getRecords() const;
|
|
||||||
|
|
||||||
bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
|
bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
|
||||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||||
@ -154,16 +154,16 @@ namespace CSMWorld
|
|||||||
///< Change the state of a record from base to modified, if it is not already.
|
///< Change the state of a record from base to modified, if it is not already.
|
||||||
/// \return True if the record was changed.
|
/// \return True if the record was changed.
|
||||||
|
|
||||||
int searchId (const std::string& id) const override;
|
int searchId(std::string_view id) const override;
|
||||||
////< Search record with \a id.
|
////< Search record with \a id.
|
||||||
/// \return index of record (if found) or -1 (not found)
|
/// \return index of record (if found) or -1 (not found)
|
||||||
|
|
||||||
void replace (int index, const RecordBase& record) override;
|
void replace (int index, std::unique_ptr<RecordBase> record) override;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
///
|
///
|
||||||
/// \attention \a record must not change the ID.
|
/// \attention \a record must not change the ID.
|
||||||
|
|
||||||
void appendRecord (const RecordBase& record,
|
void appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
UniversalId::Type type = UniversalId::Type_None) override;
|
UniversalId::Type type = UniversalId::Type_None) override;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
@ -181,7 +181,7 @@ namespace CSMWorld
|
|||||||
///
|
///
|
||||||
/// \param listDeleted include deleted record in the list
|
/// \param listDeleted include deleted record in the list
|
||||||
|
|
||||||
virtual void insertRecord (const RecordBase& record, int index,
|
virtual void insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
UniversalId::Type type = UniversalId::Type_None);
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
///< Insert record before index.
|
///< Insert record before index.
|
||||||
///
|
///
|
||||||
@ -198,20 +198,14 @@ namespace CSMWorld
|
|||||||
|
|
||||||
void addColumn (Column<ESXRecordT> *column);
|
void addColumn (Column<ESXRecordT> *column);
|
||||||
|
|
||||||
void setRecord (int index, const Record<ESXRecordT>& record);
|
void setRecord (int index, std::unique_ptr<Record<ESXRecordT> > record);
|
||||||
///< \attention This function must not change the ID.
|
///< \attention This function must not change the ID.
|
||||||
|
|
||||||
NestableColumn *getNestableColumn (int column) const;
|
NestableColumn *getNestableColumn (int column) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
const std::map<std::string, int>& Collection<ESXRecordT, IdAccessorT>::getIdMap() const
|
const std::vector<std::unique_ptr<Record<ESXRecordT> > >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
|
||||||
{
|
|
||||||
return mIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
|
||||||
const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
|
|
||||||
{
|
{
|
||||||
return mRecords;
|
return mRecords;
|
||||||
}
|
}
|
||||||
@ -231,15 +225,15 @@ namespace CSMWorld
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// reorder records
|
// reorder records
|
||||||
std::vector<Record<ESXRecordT> > buffer (size);
|
std::vector<std::unique_ptr<Record<ESXRecordT> > > buffer (size);
|
||||||
|
|
||||||
for (int i=0; i<size; ++i)
|
for (int i=0; i<size; ++i)
|
||||||
{
|
{
|
||||||
buffer[newOrder[i]] = mRecords [baseIndex+i];
|
buffer[newOrder[i]] = std::move(mRecords [baseIndex+i]);
|
||||||
buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
|
buffer[newOrder[i]]->setModified (buffer[newOrder[i]]->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
std::move (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
||||||
|
|
||||||
// adjust index
|
// adjust index
|
||||||
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
||||||
@ -255,18 +249,18 @@ namespace CSMWorld
|
|||||||
int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin,
|
int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin,
|
||||||
const std::string& destination, UniversalId::Type type)
|
const std::string& destination, UniversalId::Type type)
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> copy;
|
std::unique_ptr<Record<ESXRecordT> > copy(new Record<ESXRecordT>);
|
||||||
copy.mModified = getRecord(origin).get();
|
copy->mModified = getRecord(origin).get();
|
||||||
copy.mState = RecordBase::State_ModifiedOnly;
|
copy->mState = RecordBase::State_ModifiedOnly;
|
||||||
IdAccessorT().setId(copy.get(), destination);
|
IdAccessorT().setId(copy->get(), destination);
|
||||||
|
|
||||||
if (type == UniversalId::Type_Reference) {
|
if (type == UniversalId::Type_Reference) {
|
||||||
CSMWorld::CellRef* ptr = (CSMWorld::CellRef*) ©.mModified;
|
CSMWorld::CellRef* ptr = (CSMWorld::CellRef*) ©->mModified;
|
||||||
ptr->mRefNum.mIndex = 0;
|
ptr->mRefNum.mIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = getAppendIndex(destination, type);
|
int index = getAppendIndex(destination, type);
|
||||||
insertRecord(copy, getAppendIndex(destination, type));
|
insertRecord(std::move(copy), getAppendIndex(destination, type));
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
@ -275,7 +269,7 @@ namespace CSMWorld
|
|||||||
int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id)
|
int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id)
|
||||||
{
|
{
|
||||||
int index = getIndex(id);
|
int index = getIndex(id);
|
||||||
Record<ESXRecordT>& record = mRecords.at(index);
|
Record<ESXRecordT>& record = *mRecords.at(index);
|
||||||
if (record.isDeleted())
|
if (record.isDeleted())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("attempt to touch deleted record");
|
throw std::runtime_error("attempt to touch deleted record");
|
||||||
@ -302,7 +296,7 @@ namespace CSMWorld
|
|||||||
const std::string& destination, const UniversalId::Type type)
|
const std::string& destination, const UniversalId::Type type)
|
||||||
{
|
{
|
||||||
int index = cloneRecordImp(origin, destination, type);
|
int index = cloneRecordImp(origin, destination, type);
|
||||||
mRecords.at(index).get().mPlugin = 0;
|
mRecords.at(index)->get().mPlugin = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -317,7 +311,7 @@ namespace CSMWorld
|
|||||||
int index = touchRecordImp(id);
|
int index = touchRecordImp(id);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
mRecords.at(index).get().mPlugin = 0;
|
mRecords.at(index)->get().mPlugin = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,15 +338,15 @@ namespace CSMWorld
|
|||||||
|
|
||||||
if (iter==mIndex.end())
|
if (iter==mIndex.end())
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record2;
|
std::unique_ptr<Record<ESXRecordT> > record2(new Record<ESXRecordT>);
|
||||||
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
record2->mState = Record<ESXRecordT>::State_ModifiedOnly;
|
||||||
record2.mModified = record;
|
record2->mModified = record;
|
||||||
|
|
||||||
insertRecord (record2, getAppendIndex (id));
|
insertRecord (std::move(record2), getAppendIndex (id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mRecords[iter->second].setModified (record);
|
mRecords[iter->second]->setModified (record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +359,7 @@ namespace CSMWorld
|
|||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
|
std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
|
||||||
{
|
{
|
||||||
return IdAccessorT().getId (mRecords.at (index).get());
|
return IdAccessorT().getId (mRecords.at (index)->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -388,13 +382,13 @@ namespace CSMWorld
|
|||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
|
QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
|
||||||
{
|
{
|
||||||
return mColumns.at (column)->get (mRecords.at (index));
|
return mColumns.at (column)->get (*mRecords.at (index));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
|
void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
|
||||||
{
|
{
|
||||||
return mColumns.at (column)->set (mRecords.at (index), data);
|
return mColumns.at (column)->set (*mRecords.at (index), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -421,8 +415,8 @@ namespace CSMWorld
|
|||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::merge()
|
void Collection<ESXRecordT, IdAccessorT>::merge()
|
||||||
{
|
{
|
||||||
for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
|
for (typename std::vector<std::unique_ptr<Record<ESXRecordT> > >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
|
||||||
iter->merge();
|
(*iter)->merge();
|
||||||
|
|
||||||
purge();
|
purge();
|
||||||
}
|
}
|
||||||
@ -434,7 +428,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
while (i<static_cast<int> (mRecords.size()))
|
while (i<static_cast<int> (mRecords.size()))
|
||||||
{
|
{
|
||||||
if (mRecords[i].isErased())
|
if (mRecords[i]->isErased())
|
||||||
removeRows (i, 1);
|
removeRows (i, 1);
|
||||||
else
|
else
|
||||||
++i;
|
++i;
|
||||||
@ -475,15 +469,15 @@ namespace CSMWorld
|
|||||||
IdAccessorT().setId(record, id);
|
IdAccessorT().setId(record, id);
|
||||||
record.blank();
|
record.blank();
|
||||||
|
|
||||||
Record<ESXRecordT> record2;
|
std::unique_ptr<Record<ESXRecordT> > record2(new Record<ESXRecordT>);
|
||||||
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
record2->mState = Record<ESXRecordT>::State_ModifiedOnly;
|
||||||
record2.mModified = record;
|
record2->mModified = record;
|
||||||
|
|
||||||
insertRecord (record2, getAppendIndex (id, type), type);
|
insertRecord (std::move(record2), getAppendIndex (id, type), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
int Collection<ESXRecordT, IdAccessorT>::searchId (const std::string& id) const
|
int Collection<ESXRecordT, IdAccessorT>::searchId(std::string_view id) const
|
||||||
{
|
{
|
||||||
std::string id2 = Misc::StringUtils::lowerCase(id);
|
std::string id2 = Misc::StringUtils::lowerCase(id);
|
||||||
|
|
||||||
@ -496,18 +490,19 @@ namespace CSMWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::replace (int index, const RecordBase& record)
|
void Collection<ESXRecordT, IdAccessorT>::replace (int index, std::unique_ptr<RecordBase> record)
|
||||||
{
|
{
|
||||||
mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
|
std::unique_ptr<Record<ESXRecordT> > tmp(static_cast<Record<ESXRecordT>*>(record.release()));
|
||||||
|
mRecords.at (index) = std::move(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::appendRecord (const RecordBase& record,
|
void Collection<ESXRecordT, IdAccessorT>::appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
insertRecord (record,
|
int index =
|
||||||
getAppendIndex (IdAccessorT().getId (
|
getAppendIndex(IdAccessorT().getId(static_cast<Record<ESXRecordT>*>(record.get())->get()), type);
|
||||||
dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
|
insertRecord (std::move(record), index, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -525,8 +520,8 @@ namespace CSMWorld
|
|||||||
for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
|
for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
|
||||||
iter!=mIndex.end(); ++iter)
|
iter!=mIndex.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (listDeleted || !mRecords[iter->second].isDeleted())
|
if (listDeleted || !mRecords[iter->second]->isDeleted())
|
||||||
ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
|
ids.push_back (IdAccessorT().getId (mRecords[iter->second]->get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
@ -536,46 +531,52 @@ namespace CSMWorld
|
|||||||
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
|
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
|
||||||
{
|
{
|
||||||
int index = getIndex (id);
|
int index = getIndex (id);
|
||||||
return mRecords.at (index);
|
return *mRecords.at (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (int index) const
|
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (int index) const
|
||||||
{
|
{
|
||||||
return mRecords.at (index);
|
return *mRecords.at (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::insertRecord (const RecordBase& record, int index,
|
void Collection<ESXRecordT, IdAccessorT>::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
if (index<0 || index>static_cast<int> (mRecords.size()))
|
int size = static_cast<int>(mRecords.size());
|
||||||
|
if (index < 0 || index > size)
|
||||||
throw std::runtime_error ("index out of range");
|
throw std::runtime_error ("index out of range");
|
||||||
|
|
||||||
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
|
std::unique_ptr<Record<ESXRecordT> > record2(static_cast<Record<ESXRecordT>*>(record.release()));
|
||||||
|
std::string lowerId = Misc::StringUtils::lowerCase(IdAccessorT().getId(record2->get()));
|
||||||
|
|
||||||
mRecords.insert (mRecords.begin()+index, record2);
|
if (index == size)
|
||||||
|
mRecords.push_back (std::move(record2));
|
||||||
|
else
|
||||||
|
mRecords.insert (mRecords.begin()+index, std::move(record2));
|
||||||
|
|
||||||
if (index<static_cast<int> (mRecords.size())-1)
|
if (index < size-1)
|
||||||
{
|
{
|
||||||
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end(); ++iter)
|
||||||
++iter)
|
{
|
||||||
if (iter->second>=index)
|
if (iter->second >= index)
|
||||||
++(iter->second);
|
++(iter->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
|
mIndex.insert (std::make_pair (lowerId, index));
|
||||||
record2.get())), index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void Collection<ESXRecordT, IdAccessorT>::setRecord (int index, const Record<ESXRecordT>& record)
|
void Collection<ESXRecordT, IdAccessorT>::setRecord (int index,
|
||||||
|
std::unique_ptr<Record<ESXRecordT> > record)
|
||||||
{
|
{
|
||||||
if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index).get()))!=
|
if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index)->get())) !=
|
||||||
Misc::StringUtils::lowerCase (IdAccessorT().getId (record.get())))
|
Misc::StringUtils::lowerCase (IdAccessorT().getId (record->get())))
|
||||||
throw std::runtime_error ("attempt to change the ID of a record");
|
throw std::runtime_error ("attempt to change the ID of a record");
|
||||||
|
|
||||||
mRecords.at (index) = record;
|
mRecords.at (index) = std::move(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
@ -8,6 +8,11 @@ CSMWorld::CollectionBase::CollectionBase() {}
|
|||||||
|
|
||||||
CSMWorld::CollectionBase::~CollectionBase() {}
|
CSMWorld::CollectionBase::~CollectionBase() {}
|
||||||
|
|
||||||
|
int CSMWorld::CollectionBase::getInsertIndex (const std::string& id, UniversalId::Type type, RecordBase *record) const
|
||||||
|
{
|
||||||
|
return getAppendIndex(id, type);
|
||||||
|
}
|
||||||
|
|
||||||
int CSMWorld::CollectionBase::searchColumnIndex (Columns::ColumnId id) const
|
int CSMWorld::CollectionBase::searchColumnIndex (Columns::ColumnId id) const
|
||||||
{
|
{
|
||||||
int columns = getColumns();
|
int columns = getColumns();
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
#include "columns.hpp"
|
#include "columns.hpp"
|
||||||
@ -60,17 +62,17 @@ namespace CSMWorld
|
|||||||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
virtual int searchId (const std::string& id) const = 0;
|
virtual int searchId(std::string_view id) const = 0;
|
||||||
////< Search record with \a id.
|
////< Search record with \a id.
|
||||||
/// \return index of record (if found) or -1 (not found)
|
/// \return index of record (if found) or -1 (not found)
|
||||||
|
|
||||||
virtual void replace (int index, const RecordBase& record) = 0;
|
virtual void replace (int index, std::unique_ptr<RecordBase> record) = 0;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
///
|
///
|
||||||
/// \attention \a record must not change the ID.
|
/// \attention \a record must not change the ID.
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
virtual void appendRecord (const RecordBase& record,
|
virtual void appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
|
|
||||||
@ -99,6 +101,12 @@ namespace CSMWorld
|
|||||||
///
|
///
|
||||||
/// \return Success?
|
/// \return Success?
|
||||||
|
|
||||||
|
virtual int getInsertIndex (const std::string& id,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None,
|
||||||
|
RecordBase *record = nullptr) const;
|
||||||
|
///< Works like getAppendIndex unless an overloaded method uses the record pointer
|
||||||
|
/// to get additional info about the record that results in an alternative index.
|
||||||
|
|
||||||
int searchColumnIndex (Columns::ColumnId id) const;
|
int searchColumnIndex (Columns::ColumnId id) const;
|
||||||
///< Return index of column with the given \a id. If no such column exists, -1 is returned.
|
///< Return index of column with the given \a id. If no such column exists, -1 is returned.
|
||||||
|
|
||||||
|
@ -104,7 +104,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
|
|||||||
bool CSMWorld::ColumnBase::isText (Display display)
|
bool CSMWorld::ColumnBase::isText (Display display)
|
||||||
{
|
{
|
||||||
return display==Display_String || display==Display_LongString ||
|
return display==Display_String || display==Display_LongString ||
|
||||||
display==Display_String32 || display==Display_LongString256;
|
display==Display_String32 || display==Display_String64 ||
|
||||||
|
display==Display_LongString256;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::ColumnBase::isScript (Display display)
|
bool CSMWorld::ColumnBase::isScript (Display display)
|
||||||
|
@ -135,6 +135,7 @@ namespace CSMWorld
|
|||||||
Display_InfoCondVar,
|
Display_InfoCondVar,
|
||||||
Display_InfoCondComp,
|
Display_InfoCondComp,
|
||||||
Display_String32,
|
Display_String32,
|
||||||
|
Display_String64,
|
||||||
Display_LongString256,
|
Display_LongString256,
|
||||||
Display_BookType,
|
Display_BookType,
|
||||||
Display_BloodType,
|
Display_BloodType,
|
||||||
|
@ -334,7 +334,8 @@ namespace CSMWorld
|
|||||||
template<typename ESXRecordT>
|
template<typename ESXRecordT>
|
||||||
struct NameColumn : public Column<ESXRecordT>
|
struct NameColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
NameColumn() : Column<ESXRecordT> (Columns::ColumnId_Name, ColumnBase::Display_String) {}
|
NameColumn(ColumnBase::Display display = ColumnBase::Display_String)
|
||||||
|
: Column<ESXRecordT> (Columns::ColumnId_Name, display) {}
|
||||||
|
|
||||||
QVariant get (const Record<ESXRecordT>& record) const override
|
QVariant get (const Record<ESXRecordT>& record) const override
|
||||||
{
|
{
|
||||||
|
@ -371,6 +371,7 @@ namespace CSMWorld
|
|||||||
{ ColumnId_Skill7, "Skill 7" },
|
{ ColumnId_Skill7, "Skill 7" },
|
||||||
|
|
||||||
{ ColumnId_Persistent, "Persistent" },
|
{ ColumnId_Persistent, "Persistent" },
|
||||||
|
{ ColumnId_Blocked, "Blocked" },
|
||||||
|
|
||||||
{ -1, 0 } // end marker
|
{ -1, 0 } // end marker
|
||||||
};
|
};
|
||||||
@ -391,7 +392,7 @@ int CSMWorld::Columns::getId (const std::string& name)
|
|||||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||||
|
|
||||||
for (int i=0; sNames[i].mName; ++i)
|
for (int i=0; sNames[i].mName; ++i)
|
||||||
if (Misc::StringUtils::ciEqual(sNames[i].mName, name2))
|
if (Misc::StringUtils::ciEqual(std::string_view(sNames[i].mName), name2))
|
||||||
return sNames[i].mId;
|
return sNames[i].mId;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -344,6 +344,7 @@ namespace CSMWorld
|
|||||||
ColumnId_FactionAttrib2 = 312,
|
ColumnId_FactionAttrib2 = 312,
|
||||||
|
|
||||||
ColumnId_Persistent = 313,
|
ColumnId_Persistent = 313,
|
||||||
|
ColumnId_Blocked = 314,
|
||||||
|
|
||||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||||
// to extend the number of use values.
|
// to extend the number of use values.
|
||||||
|
@ -141,7 +141,6 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons
|
|||||||
|
|
||||||
std::unique_ptr<CSMWorld::UpdateCellCommand> modifyCell;
|
std::unique_ptr<CSMWorld::UpdateCellCommand> modifyCell;
|
||||||
|
|
||||||
std::unique_ptr<CSMWorld::ModifyCommand> modifyDataRefNum;
|
|
||||||
|
|
||||||
int columnId = model->data (index, ColumnBase::Role_ColumnId).toInt();
|
int columnId = model->data (index, ColumnBase::Role_ColumnId).toInt();
|
||||||
|
|
||||||
@ -170,14 +169,8 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons
|
|||||||
|
|
||||||
if (cellId.find ('#')!=std::string::npos)
|
if (cellId.find ('#')!=std::string::npos)
|
||||||
{
|
{
|
||||||
// Need to recalculate the cell and (if necessary) clear the instance's refNum
|
// Need to recalculate the cell
|
||||||
modifyCell.reset (new UpdateCellCommand (model2, row));
|
modifyCell.reset (new UpdateCellCommand (model2, row));
|
||||||
|
|
||||||
// Not sure which model this should be applied to
|
|
||||||
int refNumColumn = model2.searchColumnIndex (Columns::ColumnId_RefNum);
|
|
||||||
|
|
||||||
if (refNumColumn!=-1)
|
|
||||||
modifyDataRefNum.reset (new ModifyCommand(*model, model->index(row, refNumColumn), 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,8 +184,6 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons
|
|||||||
CommandMacro macro (mDocument.getUndoStack());
|
CommandMacro macro (mDocument.getUndoStack());
|
||||||
macro.push (modifyData.release());
|
macro.push (modifyData.release());
|
||||||
macro.push (modifyCell.release());
|
macro.push (modifyCell.release());
|
||||||
if (modifyDataRefNum.get())
|
|
||||||
macro.push (modifyDataRefNum.release());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mDocument.getUndoStack().push (modifyData.release());
|
mDocument.getUndoStack().push (modifyData.release());
|
||||||
|
@ -24,11 +24,11 @@ CSMWorld::TouchCommand::TouchCommand(IdTable& table, const std::string& id, QUnd
|
|||||||
, mChanged(false)
|
, mChanged(false)
|
||||||
{
|
{
|
||||||
setText(("Touch " + mId).c_str());
|
setText(("Touch " + mId).c_str());
|
||||||
mOld.reset(mTable.getRecord(mId).clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::TouchCommand::redo()
|
void CSMWorld::TouchCommand::redo()
|
||||||
{
|
{
|
||||||
|
mOld.reset(mTable.getRecord(mId).clone().get());
|
||||||
mChanged = mTable.touchRecord(mId);
|
mChanged = mTable.touchRecord(mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ void CSMWorld::TouchCommand::undo()
|
|||||||
{
|
{
|
||||||
if (mChanged)
|
if (mChanged)
|
||||||
{
|
{
|
||||||
mTable.setRecord(mId, *mOld);
|
mTable.setRecord(mId, std::move(mOld));
|
||||||
mChanged = false;
|
mChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +159,6 @@ CSMWorld::TouchLandCommand::TouchLandCommand(IdTable& landTable, IdTable& ltexTa
|
|||||||
, mChanged(false)
|
, mChanged(false)
|
||||||
{
|
{
|
||||||
setText(("Touch " + mId).c_str());
|
setText(("Touch " + mId).c_str());
|
||||||
mOld.reset(mLands.getRecord(mId).clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& CSMWorld::TouchLandCommand::getOriginId() const
|
const std::string& CSMWorld::TouchLandCommand::getOriginId() const
|
||||||
@ -175,13 +174,14 @@ const std::string& CSMWorld::TouchLandCommand::getDestinationId() const
|
|||||||
void CSMWorld::TouchLandCommand::onRedo()
|
void CSMWorld::TouchLandCommand::onRedo()
|
||||||
{
|
{
|
||||||
mChanged = mLands.touchRecord(mId);
|
mChanged = mLands.touchRecord(mId);
|
||||||
|
if (mChanged) mOld.reset(mLands.getRecord(mId).clone().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::TouchLandCommand::onUndo()
|
void CSMWorld::TouchLandCommand::onUndo()
|
||||||
{
|
{
|
||||||
if (mChanged)
|
if (mChanged)
|
||||||
{
|
{
|
||||||
mLands.setRecord(mId, *mOld);
|
mLands.setRecord(mId, std::move(mOld));
|
||||||
mChanged = false;
|
mChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,13 +190,16 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI
|
|||||||
const QVariant& new_, QUndoCommand* parent)
|
const QVariant& new_, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly)
|
: QUndoCommand (parent), mModel (&model), mIndex (index), mNew (new_), mHasRecordState(false), mOldRecordState(CSMWorld::RecordBase::State_BaseOnly)
|
||||||
{
|
{
|
||||||
if (QAbstractProxyModel *proxy = dynamic_cast<QAbstractProxyModel *> (&model))
|
if (QAbstractProxyModel *proxy = dynamic_cast<QAbstractProxyModel *> (mModel))
|
||||||
{
|
{
|
||||||
// Replace proxy with actual model
|
// Replace proxy with actual model
|
||||||
mIndex = proxy->mapToSource (index);
|
mIndex = proxy->mapToSource (mIndex);
|
||||||
mModel = proxy->sourceModel();
|
mModel = proxy->sourceModel();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::ModifyCommand::redo()
|
||||||
|
{
|
||||||
if (mIndex.parent().isValid())
|
if (mIndex.parent().isValid())
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree* tree = &dynamic_cast<CSMWorld::IdTree&>(*mModel);
|
CSMWorld::IdTree* tree = &dynamic_cast<CSMWorld::IdTree&>(*mModel);
|
||||||
@ -223,10 +226,7 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI
|
|||||||
mRecordStateIndex = table->index(rowIndex, stateColumnIndex);
|
mRecordStateIndex = table->index(rowIndex, stateColumnIndex);
|
||||||
mOldRecordState = static_cast<CSMWorld::RecordBase::State>(table->data(mRecordStateIndex).toInt());
|
mOldRecordState = static_cast<CSMWorld::RecordBase::State>(table->data(mRecordStateIndex).toInt());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CSMWorld::ModifyCommand::redo()
|
|
||||||
{
|
|
||||||
mOld = mModel->data (mIndex, Qt::EditRole);
|
mOld = mModel->data (mIndex, Qt::EditRole);
|
||||||
mModel->setData (mIndex, mNew);
|
mModel->setData (mIndex, mNew);
|
||||||
}
|
}
|
||||||
@ -291,20 +291,19 @@ void CSMWorld::CreateCommand::undo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
|
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (nullptr)
|
: QUndoCommand (parent), mModel (model), mId (id), mOld(nullptr)
|
||||||
{
|
{
|
||||||
setText (("Revert record " + id).c_str());
|
setText (("Revert record " + id).c_str());
|
||||||
|
|
||||||
mOld = model.getRecord (id).clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::RevertCommand::~RevertCommand()
|
CSMWorld::RevertCommand::~RevertCommand()
|
||||||
{
|
{
|
||||||
delete mOld;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RevertCommand::redo()
|
void CSMWorld::RevertCommand::redo()
|
||||||
{
|
{
|
||||||
|
mOld = mModel.getRecord (mId).clone();
|
||||||
|
|
||||||
int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
|
int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
|
||||||
|
|
||||||
QModelIndex index = mModel.getModelIndex (mId, column);
|
QModelIndex index = mModel.getModelIndex (mId, column);
|
||||||
@ -322,25 +321,24 @@ void CSMWorld::RevertCommand::redo()
|
|||||||
|
|
||||||
void CSMWorld::RevertCommand::undo()
|
void CSMWorld::RevertCommand::undo()
|
||||||
{
|
{
|
||||||
mModel.setRecord (mId, *mOld);
|
mModel.setRecord (mId, std::move(mOld));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model,
|
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model,
|
||||||
const std::string& id, CSMWorld::UniversalId::Type type, QUndoCommand* parent)
|
const std::string& id, CSMWorld::UniversalId::Type type, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (nullptr), mType(type)
|
: QUndoCommand (parent), mModel (model), mId (id), mOld(nullptr), mType(type)
|
||||||
{
|
{
|
||||||
setText (("Delete record " + id).c_str());
|
setText (("Delete record " + id).c_str());
|
||||||
|
|
||||||
mOld = model.getRecord (id).clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::DeleteCommand::~DeleteCommand()
|
CSMWorld::DeleteCommand::~DeleteCommand()
|
||||||
{
|
{
|
||||||
delete mOld;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::DeleteCommand::redo()
|
void CSMWorld::DeleteCommand::redo()
|
||||||
{
|
{
|
||||||
|
mOld = mModel.getRecord (mId).clone();
|
||||||
|
|
||||||
int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
|
int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
|
||||||
|
|
||||||
QModelIndex index = mModel.getModelIndex (mId, column);
|
QModelIndex index = mModel.getModelIndex (mId, column);
|
||||||
@ -358,7 +356,7 @@ void CSMWorld::DeleteCommand::redo()
|
|||||||
|
|
||||||
void CSMWorld::DeleteCommand::undo()
|
void CSMWorld::DeleteCommand::undo()
|
||||||
{
|
{
|
||||||
mModel.setRecord (mId, *mOld, mType);
|
mModel.setRecord (mId, std::move(mOld), mType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -424,18 +422,19 @@ void CSMWorld::CreatePathgridCommand::redo()
|
|||||||
{
|
{
|
||||||
CreateCommand::redo();
|
CreateCommand::redo();
|
||||||
|
|
||||||
Record<Pathgrid> record = static_cast<const Record<Pathgrid>& >(mModel.getRecord(mId));
|
std::unique_ptr<Record<Pathgrid> > record
|
||||||
record.get().blank();
|
= std::make_unique<Record<Pathgrid> >(static_cast<const Record<Pathgrid>& >(mModel.getRecord(mId)));
|
||||||
record.get().mCell = mId;
|
record->get().blank();
|
||||||
|
record->get().mCell = mId;
|
||||||
|
|
||||||
std::pair<CellCoordinates, bool> coords = CellCoordinates::fromId(mId);
|
std::pair<CellCoordinates, bool> coords = CellCoordinates::fromId(mId);
|
||||||
if (coords.second)
|
if (coords.second)
|
||||||
{
|
{
|
||||||
record.get().mData.mX = coords.first.getX();
|
record->get().mData.mX = coords.first.getX();
|
||||||
record.get().mData.mY = coords.first.getY();
|
record->get().mData.mY = coords.first.getY();
|
||||||
}
|
}
|
||||||
|
|
||||||
mModel.setRecord(mId, record, mType);
|
mModel.setRecord(mId, std::move(record), mType);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
||||||
@ -499,8 +498,8 @@ CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model,
|
|||||||
void CSMWorld::DeleteNestedCommand::redo()
|
void CSMWorld::DeleteNestedCommand::redo()
|
||||||
{
|
{
|
||||||
QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
||||||
mModel.removeRows (mNestedRow, 1, parentIndex);
|
|
||||||
mModifyParentCommand->redo();
|
mModifyParentCommand->redo();
|
||||||
|
mModel.removeRows (mNestedRow, 1, parentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -530,8 +529,8 @@ CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& i
|
|||||||
void CSMWorld::AddNestedCommand::redo()
|
void CSMWorld::AddNestedCommand::redo()
|
||||||
{
|
{
|
||||||
QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
QModelIndex parentIndex = mModel.getModelIndex(mId, mParentColumn);
|
||||||
mModel.addNestedRow (parentIndex, mNewRow);
|
|
||||||
mModifyParentCommand->redo();
|
mModifyParentCommand->redo();
|
||||||
|
mModel.addNestedRow (parentIndex, mNewRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::AddNestedCommand::undo()
|
void CSMWorld::AddNestedCommand::undo()
|
||||||
|
@ -203,7 +203,7 @@ namespace CSMWorld
|
|||||||
{
|
{
|
||||||
IdTable& mModel;
|
IdTable& mModel;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
RecordBase *mOld;
|
std::unique_ptr<RecordBase> mOld;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
RevertCommand (const RevertCommand&);
|
RevertCommand (const RevertCommand&);
|
||||||
@ -224,7 +224,7 @@ namespace CSMWorld
|
|||||||
{
|
{
|
||||||
IdTable& mModel;
|
IdTable& mModel;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
RecordBase *mOld;
|
std::unique_ptr<RecordBase> mOld;
|
||||||
UniversalId::Type mType;
|
UniversalId::Type mType;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
|
@ -84,6 +84,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||||
defines["radialFog"] = "0";
|
defines["radialFog"] = "0";
|
||||||
defines["lightingModel"] = "0";
|
defines["lightingModel"] = "0";
|
||||||
|
defines["reverseZ"] = "0";
|
||||||
for (const auto& define : shadowDefines)
|
for (const auto& define : shadowDefines)
|
||||||
defines[define.first] = define.second;
|
defines[define.first] = define.second;
|
||||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||||
@ -130,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||||||
mFactions.addColumn (new StringIdColumn<ESM::Faction>);
|
mFactions.addColumn (new StringIdColumn<ESM::Faction>);
|
||||||
mFactions.addColumn (new RecordStateColumn<ESM::Faction>);
|
mFactions.addColumn (new RecordStateColumn<ESM::Faction>);
|
||||||
mFactions.addColumn (new FixedRecordTypeColumn<ESM::Faction> (UniversalId::Type_Faction));
|
mFactions.addColumn (new FixedRecordTypeColumn<ESM::Faction> (UniversalId::Type_Faction));
|
||||||
mFactions.addColumn (new NameColumn<ESM::Faction>);
|
mFactions.addColumn (new NameColumn<ESM::Faction>(ColumnBase::Display_String32));
|
||||||
mFactions.addColumn (new AttributesColumn<ESM::Faction> (0));
|
mFactions.addColumn (new AttributesColumn<ESM::Faction> (0));
|
||||||
mFactions.addColumn (new AttributesColumn<ESM::Faction> (1));
|
mFactions.addColumn (new AttributesColumn<ESM::Faction> (1));
|
||||||
mFactions.addColumn (new HiddenColumn<ESM::Faction>);
|
mFactions.addColumn (new HiddenColumn<ESM::Faction>);
|
||||||
@ -339,7 +340,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||||||
mCells.addColumn (new StringIdColumn<Cell>);
|
mCells.addColumn (new StringIdColumn<Cell>);
|
||||||
mCells.addColumn (new RecordStateColumn<Cell>);
|
mCells.addColumn (new RecordStateColumn<Cell>);
|
||||||
mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell));
|
mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell));
|
||||||
mCells.addColumn (new NameColumn<Cell>);
|
mCells.addColumn (new NameColumn<Cell>(ColumnBase::Display_String64));
|
||||||
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep));
|
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep));
|
||||||
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater,
|
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater,
|
||||||
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
|
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
|
||||||
@ -917,8 +918,8 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
|
|||||||
|
|
||||||
void CSMWorld::Data::setMetaData (const MetaData& metaData)
|
void CSMWorld::Data::setMetaData (const MetaData& metaData)
|
||||||
{
|
{
|
||||||
Record<MetaData> record (RecordBase::State_ModifiedOnly, nullptr, &metaData);
|
mMetaData.setRecord (0, std::make_unique<Record<MetaData> >(
|
||||||
mMetaData.setRecord (0, record);
|
Record<MetaData>(RecordBase::State_ModifiedOnly, nullptr, &metaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
|
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
|
||||||
@ -958,6 +959,25 @@ void CSMWorld::Data::merge()
|
|||||||
mGlobals.merge();
|
mGlobals.merge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CSMWorld::Data::getTotalRecords (const std::vector<boost::filesystem::path>& files)
|
||||||
|
{
|
||||||
|
int records = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<ESM::ESMReader> reader = std::unique_ptr<ESM::ESMReader>(new ESM::ESMReader);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < files.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::exists(files[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
reader->open(files[i].string());
|
||||||
|
records += reader->getRecordCount();
|
||||||
|
reader->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project)
|
int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project)
|
||||||
{
|
{
|
||||||
// Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading
|
// Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading
|
||||||
@ -983,7 +1003,8 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
|||||||
metaData.mId = "sys::meta";
|
metaData.mId = "sys::meta";
|
||||||
metaData.load (*mReader);
|
metaData.load (*mReader);
|
||||||
|
|
||||||
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, nullptr, &metaData));
|
mMetaData.setRecord (0, std::make_unique<Record<MetaData> >(
|
||||||
|
Record<MetaData> (RecordBase::State_ModifiedOnly, nullptr, &metaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mReader->getRecordCount();
|
return mReader->getRecordCount();
|
||||||
@ -1011,10 +1032,10 @@ void CSMWorld::Data::loadFallbackEntries()
|
|||||||
ESM::Static newMarker;
|
ESM::Static newMarker;
|
||||||
newMarker.mId = marker.first;
|
newMarker.mId = marker.first;
|
||||||
newMarker.mModel = marker.second;
|
newMarker.mModel = marker.second;
|
||||||
CSMWorld::Record<ESM::Static> record;
|
std::unique_ptr<CSMWorld::Record<ESM::Static> > record(new CSMWorld::Record<ESM::Static>);
|
||||||
record.mBase = newMarker;
|
record->mBase = newMarker;
|
||||||
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Static);
|
mReferenceables.appendRecord (std::move(record), CSMWorld::UniversalId::Type_Static);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,10 +1046,10 @@ void CSMWorld::Data::loadFallbackEntries()
|
|||||||
ESM::Door newMarker;
|
ESM::Door newMarker;
|
||||||
newMarker.mId = marker.first;
|
newMarker.mId = marker.first;
|
||||||
newMarker.mModel = marker.second;
|
newMarker.mModel = marker.second;
|
||||||
CSMWorld::Record<ESM::Door> record;
|
std::unique_ptr<CSMWorld::Record<ESM::Door> > record(new CSMWorld::Record<ESM::Door>);
|
||||||
record.mBase = newMarker;
|
record->mBase = newMarker;
|
||||||
record.mState = CSMWorld::RecordBase::State_BaseOnly;
|
record->mState = CSMWorld::RecordBase::State_BaseOnly;
|
||||||
mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Door);
|
mReferenceables.appendRecord (std::move(record), CSMWorld::UniversalId::Type_Door);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ namespace CSMWorld
|
|||||||
const ESM::Dialogue *mDialogue; // last loaded dialogue
|
const ESM::Dialogue *mDialogue; // last loaded dialogue
|
||||||
bool mBase;
|
bool mBase;
|
||||||
bool mProject;
|
bool mProject;
|
||||||
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
|
std::map<std::string, std::map<unsigned int, unsigned int> > mRefLoadCache;
|
||||||
int mReaderIndex;
|
int mReaderIndex;
|
||||||
|
|
||||||
bool mFsStrict;
|
bool mFsStrict;
|
||||||
@ -292,6 +292,8 @@ namespace CSMWorld
|
|||||||
void merge();
|
void merge();
|
||||||
///< Merge modified into base.
|
///< Merge modified into base.
|
||||||
|
|
||||||
|
int getTotalRecords (const std::vector<boost::filesystem::path>& files); // for better loading bar
|
||||||
|
|
||||||
int startLoading (const boost::filesystem::path& path, bool base, bool project);
|
int startLoading (const boost::filesystem::path& path, bool base, bool project);
|
||||||
///< Begin merging content of a file into base or modified.
|
///< Begin merging content of a file into base or modified.
|
||||||
///
|
///
|
||||||
|
43
apps/opencs/model/world/idcollection.cpp
Normal file
43
apps/opencs/model/world/idcollection.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "idcollection.hpp"
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
int IdCollection<Pathgrid, IdAccessor<Pathgrid> >::load (ESM::ESMReader& reader, bool base)
|
||||||
|
{
|
||||||
|
Pathgrid record;
|
||||||
|
bool isDeleted = false;
|
||||||
|
|
||||||
|
loadRecord (record, reader, isDeleted);
|
||||||
|
|
||||||
|
std::string id = IdAccessor<Pathgrid>().getId (record);
|
||||||
|
int index = this->searchId (id);
|
||||||
|
|
||||||
|
if (record.mPoints.empty() || record.mEdges.empty())
|
||||||
|
isDeleted = true;
|
||||||
|
|
||||||
|
if (isDeleted)
|
||||||
|
{
|
||||||
|
if (index==-1)
|
||||||
|
{
|
||||||
|
// deleting a record that does not exist
|
||||||
|
// ignore it for now
|
||||||
|
/// \todo report the problem to the user
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base)
|
||||||
|
{
|
||||||
|
this->removeRows (index, 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Record<Pathgrid> > baseRecord(new Record<Pathgrid>(this->getRecord(index)));
|
||||||
|
baseRecord->mState = RecordBase::State_Deleted;
|
||||||
|
this->setRecord(index, std::move(baseRecord));
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return load (record, base, index);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "collection.hpp"
|
#include "collection.hpp"
|
||||||
#include "land.hpp"
|
#include "land.hpp"
|
||||||
|
#include "pathgrid.hpp"
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
@ -83,9 +84,9 @@ namespace CSMWorld
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Record<ESXRecordT> baseRecord = this->getRecord (index);
|
std::unique_ptr<Record<ESXRecordT> > baseRecord(new Record<ESXRecordT>(this->getRecord(index)));
|
||||||
baseRecord.mState = RecordBase::State_Deleted;
|
baseRecord->mState = RecordBase::State_Deleted;
|
||||||
this->setRecord (index, baseRecord);
|
this->setRecord(index, std::move(baseRecord));
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,30 +97,31 @@ namespace CSMWorld
|
|||||||
int IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base,
|
int IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base,
|
||||||
int index)
|
int index)
|
||||||
{
|
{
|
||||||
if (index==-2)
|
if (index==-2) // index unknown
|
||||||
index = this->searchId (IdAccessorT().getId (record));
|
index = this->searchId (IdAccessorT().getId (record));
|
||||||
|
|
||||||
if (index==-1)
|
if (index==-1)
|
||||||
{
|
{
|
||||||
// new record
|
// new record
|
||||||
Record<ESXRecordT> record2;
|
std::unique_ptr<Record<ESXRecordT> > record2(new Record<ESXRecordT>);
|
||||||
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
record2->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
(base ? record2.mBase : record2.mModified) = record;
|
(base ? record2->mBase : record2->mModified) = record;
|
||||||
|
|
||||||
index = this->getSize();
|
index = this->getSize();
|
||||||
this->appendRecord (record2);
|
this->appendRecord(std::move(record2));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// old record
|
// old record
|
||||||
Record<ESXRecordT> record2 = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
|
std::unique_ptr<Record<ESXRecordT> > record2(
|
||||||
|
new Record<ESXRecordT>(Collection<ESXRecordT, IdAccessorT>::getRecord(index)));
|
||||||
|
|
||||||
if (base)
|
if (base)
|
||||||
record2.mBase = record;
|
record2->mBase = record;
|
||||||
else
|
else
|
||||||
record2.setModified (record);
|
record2->setModified(record);
|
||||||
|
|
||||||
this->setRecord (index, record2);
|
this->setRecord(index, std::move(record2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
@ -133,7 +135,7 @@ namespace CSMWorld
|
|||||||
if (index==-1)
|
if (index==-1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
|
const Record<ESXRecordT>& record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
|
||||||
|
|
||||||
if (record.isDeleted())
|
if (record.isDeleted())
|
||||||
return false;
|
return false;
|
||||||
@ -144,12 +146,17 @@ namespace CSMWorld
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
record.mState = RecordBase::State_Deleted;
|
std::unique_ptr<Record<ESXRecordT> > record2(
|
||||||
this->setRecord (index, record);
|
new Record<ESXRecordT>(Collection<ESXRecordT, IdAccessorT>::getRecord(index)));
|
||||||
|
record2->mState = RecordBase::State_Deleted;
|
||||||
|
this->setRecord(index, std::move(record2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int IdCollection<Pathgrid, IdAccessor<Pathgrid> >::load(ESM::ESMReader& reader, bool base);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -123,6 +123,14 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
|
|||||||
if (mIdCollection->getColumn (index.column()).isUserEditable())
|
if (mIdCollection->getColumn (index.column()).isUserEditable())
|
||||||
flags |= Qt::ItemIsEditable;
|
flags |= Qt::ItemIsEditable;
|
||||||
|
|
||||||
|
int blockedColumn = searchColumnIndex(Columns::ColumnId_Blocked);
|
||||||
|
if (blockedColumn != -1 && blockedColumn != index.column())
|
||||||
|
{
|
||||||
|
bool isBlocked = mIdCollection->getData(index.row(), blockedColumn).toInt();
|
||||||
|
if (isBlocked)
|
||||||
|
flags = Qt::ItemIsSelectable; // not enabled (to grey out)
|
||||||
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +199,7 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin,
|
|||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
CSMWorld::UniversalId::Type type)
|
CSMWorld::UniversalId::Type type)
|
||||||
{
|
{
|
||||||
int index = mIdCollection->getAppendIndex (destination);
|
int index = mIdCollection->getAppendIndex (destination, type);
|
||||||
|
|
||||||
beginInsertRows (QModelIndex(), index, index);
|
beginInsertRows (QModelIndex(), index, index);
|
||||||
mIdCollection->cloneRecord(origin, destination, type);
|
mIdCollection->cloneRecord(origin, destination, type);
|
||||||
@ -228,23 +236,30 @@ QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column)
|
|||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record, CSMWorld::UniversalId::Type type)
|
void CSMWorld::IdTable::setRecord (const std::string& id,
|
||||||
|
std::unique_ptr<RecordBase> record, CSMWorld::UniversalId::Type type)
|
||||||
{
|
{
|
||||||
int index = mIdCollection->searchId (id);
|
int index = mIdCollection->searchId (id);
|
||||||
|
|
||||||
if (index==-1)
|
if (index==-1)
|
||||||
{
|
{
|
||||||
index = mIdCollection->getAppendIndex (id, type);
|
// For info records, appendRecord may use a different index than the one returned by
|
||||||
|
// getAppendIndex (because of prev/next links). This can result in the display not
|
||||||
|
// updating correctly after an undo
|
||||||
|
//
|
||||||
|
// Use an alternative method to get the correct index. For non-Info records the
|
||||||
|
// record pointer is ignored and internally calls getAppendIndex.
|
||||||
|
int index2 = mIdCollection->getInsertIndex (id, type, record.get());
|
||||||
|
|
||||||
beginInsertRows (QModelIndex(), index, index);
|
beginInsertRows (QModelIndex(), index2, index2);
|
||||||
|
|
||||||
mIdCollection->appendRecord (record, type);
|
mIdCollection->appendRecord (std::move(record), type);
|
||||||
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mIdCollection->replace (index, record);
|
mIdCollection->replace (index, std::move(record));
|
||||||
emit dataChanged (CSMWorld::IdTable::index (index, 0),
|
emit dataChanged (CSMWorld::IdTable::index (index, 0),
|
||||||
CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1));
|
CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1));
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define CSM_WOLRD_IDTABLE_H
|
#define CSM_WOLRD_IDTABLE_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "idtablebase.hpp"
|
#include "idtablebase.hpp"
|
||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
@ -67,7 +68,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
QModelIndex getModelIndex (const std::string& id, int column) const override;
|
QModelIndex getModelIndex (const std::string& id, int column) const override;
|
||||||
|
|
||||||
void setRecord (const std::string& id, const RecordBase& record,
|
void setRecord (const std::string& id, std::unique_ptr<RecordBase> record,
|
||||||
UniversalId::Type type = UniversalId::Type_None);
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
///< Add record or overwrite existing record.
|
///< Add record or overwrite existing record.
|
||||||
|
|
||||||
|
@ -121,8 +121,11 @@ QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const
|
|||||||
|
|
||||||
void CSMWorld::IdTableProxyModel::refreshFilter()
|
void CSMWorld::IdTableProxyModel::refreshFilter()
|
||||||
{
|
{
|
||||||
updateColumnMap();
|
if (mFilter)
|
||||||
invalidateFilter();
|
{
|
||||||
|
updateColumnMap();
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end)
|
void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end)
|
||||||
|
@ -2,12 +2,74 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/loaddial.hpp>
|
#include <components/esm/loaddial.hpp>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
void Collection<Info, IdAccessor<Info> >::removeRows (int index, int count)
|
||||||
|
{
|
||||||
|
mRecords.erase(mRecords.begin()+index, mRecords.begin()+index+count);
|
||||||
|
|
||||||
|
// index map is updated in InfoCollection::removeRows()
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Collection<Info, IdAccessor<Info> >::insertRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
int index, UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int size = static_cast<int>(mRecords.size());
|
||||||
|
if (index < 0 || index > size)
|
||||||
|
throw std::runtime_error("index out of range");
|
||||||
|
|
||||||
|
std::unique_ptr<Record<Info> > record2(static_cast<Record<Info>*>(record.release()));
|
||||||
|
|
||||||
|
if (index == size)
|
||||||
|
mRecords.push_back(std::move(record2));
|
||||||
|
else
|
||||||
|
mRecords.insert(mRecords.begin()+index, std::move(record2));
|
||||||
|
|
||||||
|
// index map is updated in InfoCollection::insertRecord()
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Collection<Info, IdAccessor<Info> >::reorderRowsImp (int baseIndex,
|
||||||
|
const std::vector<int>& newOrder)
|
||||||
|
{
|
||||||
|
if (!newOrder.empty())
|
||||||
|
{
|
||||||
|
int size = static_cast<int>(newOrder.size());
|
||||||
|
|
||||||
|
// check that all indices are present
|
||||||
|
std::vector<int> test(newOrder);
|
||||||
|
std::sort(test.begin(), test.end());
|
||||||
|
if (*test.begin() != 0 || *--test.end() != size-1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// reorder records
|
||||||
|
std::vector<std::unique_ptr<Record<Info> > > buffer(size);
|
||||||
|
|
||||||
|
// FIXME: BUG: undo does not remove modified flag
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
buffer[newOrder[i]] = std::move(mRecords[baseIndex+i]);
|
||||||
|
buffer[newOrder[i]]->setModified(buffer[newOrder[i]]->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::move(buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
||||||
|
|
||||||
|
// index map is updated in InfoCollection::reorderRows()
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::InfoCollection::load (const Info& record, bool base)
|
void CSMWorld::InfoCollection::load (const Info& record, bool base)
|
||||||
{
|
{
|
||||||
int index = searchId (record.mId);
|
int index = searchId (record.mId);
|
||||||
@ -15,74 +77,96 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base)
|
|||||||
if (index==-1)
|
if (index==-1)
|
||||||
{
|
{
|
||||||
// new record
|
// new record
|
||||||
Record<Info> record2;
|
std::unique_ptr<Record<Info> > record2(new Record<Info>);
|
||||||
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
record2->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
(base ? record2.mBase : record2.mModified) = record;
|
(base ? record2->mBase : record2->mModified) = record;
|
||||||
|
|
||||||
std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId);
|
appendRecord(std::move(record2));
|
||||||
|
|
||||||
if (!record2.get().mPrev.empty())
|
|
||||||
{
|
|
||||||
index = getInfoIndex (record2.get().mPrev, topic);
|
|
||||||
|
|
||||||
if (index!=-1)
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index==-1 && !record2.get().mNext.empty())
|
|
||||||
{
|
|
||||||
index = getInfoIndex (record2.get().mNext, topic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index==-1)
|
|
||||||
{
|
|
||||||
Range range = getTopicRange (topic);
|
|
||||||
|
|
||||||
index = std::distance (getRecords().begin(), range.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertRecord (record2, index);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// old record
|
// old record
|
||||||
Record<Info> record2 = getRecord (index);
|
std::unique_ptr<Record<Info> > record2(new Record<Info>(getRecord(index)));
|
||||||
|
|
||||||
if (base)
|
if (base)
|
||||||
record2.mBase = record;
|
record2->mBase = record;
|
||||||
else
|
else
|
||||||
record2.setModified (record);
|
record2->setModified (record);
|
||||||
|
|
||||||
setRecord (index, record2);
|
setRecord (index, std::move(record2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const
|
int CSMWorld::InfoCollection::getInfoIndex(std::string_view id, std::string_view topic) const
|
||||||
{
|
{
|
||||||
std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id;
|
// find the topic first
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, int> > >::const_iterator iter
|
||||||
|
= mInfoIndex.find(Misc::StringUtils::lowerCase(topic));
|
||||||
|
|
||||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
|
if (iter == mInfoIndex.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
for (; range.first!=range.second; ++range.first)
|
// brute force loop
|
||||||
if (Misc::StringUtils::ciEqual(range.first->get().mId, fullId))
|
for (std::vector<std::pair<std::string, int> >::const_iterator it = iter->second.begin();
|
||||||
return std::distance (getRecords().begin(), range.first);
|
it != iter->second.end(); ++it)
|
||||||
|
{
|
||||||
|
if (Misc::StringUtils::ciEqual(it->first, id))
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::InfoCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const
|
// Calling insertRecord() using index from getInsertIndex() needs to take into account of
|
||||||
|
// prev/next records; an example is deleting a record then undo
|
||||||
|
int CSMWorld::InfoCollection::getInsertIndex (const std::string& id,
|
||||||
|
UniversalId::Type type, RecordBase *record) const
|
||||||
{
|
{
|
||||||
std::string::size_type separator = id.find_last_of ('#');
|
if (record == nullptr)
|
||||||
|
{
|
||||||
|
std::string::size_type separator = id.find_last_of('#');
|
||||||
|
|
||||||
if (separator==std::string::npos)
|
if (separator == std::string::npos)
|
||||||
throw std::runtime_error ("invalid info ID: " + id);
|
throw std::runtime_error("invalid info ID: " + id);
|
||||||
|
|
||||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (id.substr (0, separator));
|
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange(id.substr(0, separator));
|
||||||
|
|
||||||
if (range.first==range.second)
|
if (range.first == range.second)
|
||||||
return Collection<Info, IdAccessor<Info> >::getAppendIndex (id, type);
|
return Collection<Info, IdAccessor<Info> >::getAppendIndex(id, type);
|
||||||
|
|
||||||
return std::distance (getRecords().begin(), range.second);
|
return std::distance(getRecords().begin(), range.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
const Info& info = static_cast<Record<Info>*>(record)->get();
|
||||||
|
std::string topic = info.mTopicId;
|
||||||
|
|
||||||
|
// if the record has a prev, find its index value
|
||||||
|
if (!info.mPrev.empty())
|
||||||
|
{
|
||||||
|
index = getInfoIndex(info.mPrev, topic);
|
||||||
|
|
||||||
|
if (index != -1)
|
||||||
|
++index; // if prev exists, set current index to one above prev
|
||||||
|
}
|
||||||
|
|
||||||
|
// if prev doesn't exist or not found and the record has a next, find its index value
|
||||||
|
if (index == -1 && !info.mNext.empty())
|
||||||
|
{
|
||||||
|
// if next exists, use its index as the current index
|
||||||
|
index = getInfoIndex(info.mNext, topic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if next doesn't exist or not found (i.e. neither exist yet) then start a new one
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
Range range = getTopicRange(topic); // getTopicRange converts topic to lower case first
|
||||||
|
|
||||||
|
index = std::distance(getRecords().begin(), range.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||||
@ -99,7 +183,17 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// reorder
|
// reorder
|
||||||
return reorderRowsImp (baseIndex, newOrder);
|
if (!Collection<Info, IdAccessor<Info> >::reorderRowsImp(baseIndex, newOrder))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// adjust index
|
||||||
|
int size = static_cast<int>(newOrder.size());
|
||||||
|
for (auto& [hash, infos] : mInfoIndex)
|
||||||
|
for (auto& [a, b] : infos)
|
||||||
|
if (b >= baseIndex && b < baseIndex + size)
|
||||||
|
b = newOrder.at(b - baseIndex) + baseIndex;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
|
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
|
||||||
@ -126,9 +220,9 @@ void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ES
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Record<Info> record = getRecord (index);
|
std::unique_ptr<Record<Info> > record(new Record<Info>(getRecord(index)));
|
||||||
record.mState = RecordBase::State_Deleted;
|
record->mState = RecordBase::State_Deleted;
|
||||||
setRecord (index, record);
|
setRecord (index, std::move(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -142,73 +236,54 @@ void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ES
|
|||||||
CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const std::string& topic)
|
CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const std::string& topic)
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
std::string topic2 = Misc::StringUtils::lowerCase (topic);
|
std::string lowerTopic = Misc::StringUtils::lowerCase (topic);
|
||||||
|
|
||||||
std::map<std::string, int>::const_iterator iter = getIdMap().lower_bound (topic2);
|
// find the topic
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, int> > >::const_iterator iter
|
||||||
|
= mInfoIndex.find(lowerTopic);
|
||||||
|
|
||||||
// Skip invalid records: The beginning of a topic string could be identical to another topic
|
if (iter == mInfoIndex.end())
|
||||||
// string.
|
|
||||||
for (; iter!=getIdMap().end(); ++iter)
|
|
||||||
{
|
|
||||||
std::string testTopicId =
|
|
||||||
Misc::StringUtils::lowerCase (getRecord (iter->second).get().mTopicId);
|
|
||||||
|
|
||||||
if (testTopicId==topic2)
|
|
||||||
break;
|
|
||||||
|
|
||||||
std::size_t size = topic2.size();
|
|
||||||
|
|
||||||
if (testTopicId.size()<size || testTopicId.substr (0, size)!=topic2)
|
|
||||||
return Range (getRecords().end(), getRecords().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter==getIdMap().end())
|
|
||||||
return Range (getRecords().end(), getRecords().end());
|
return Range (getRecords().end(), getRecords().end());
|
||||||
|
|
||||||
RecordConstIterator begin = getRecords().begin()+iter->second;
|
// topic found, find the starting index
|
||||||
|
int low = INT_MAX;
|
||||||
while (begin != getRecords().begin())
|
for (std::vector<std::pair<std::string, int> >::const_iterator it = iter->second.begin();
|
||||||
|
it != iter->second.end(); ++it)
|
||||||
{
|
{
|
||||||
if (!Misc::StringUtils::ciEqual(begin->get().mTopicId, topic2))
|
low = std::min(low, it->second);
|
||||||
{
|
|
||||||
// we've gone one too far, go back
|
|
||||||
++begin;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
--begin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find end
|
RecordConstIterator begin = getRecords().begin() + low;
|
||||||
RecordConstIterator end = begin;
|
|
||||||
|
|
||||||
for (; end!=getRecords().end(); ++end)
|
// Find end (one past the range)
|
||||||
if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
|
RecordConstIterator end = begin + iter->second.size();
|
||||||
break;
|
|
||||||
|
assert(static_cast<size_t>(std::distance(begin, end)) == iter->second.size());
|
||||||
|
|
||||||
return Range (begin, end);
|
return Range (begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::InfoCollection::removeDialogueInfos(const std::string& dialogueId)
|
void CSMWorld::InfoCollection::removeDialogueInfos(const std::string& dialogueId)
|
||||||
{
|
{
|
||||||
std::string id = Misc::StringUtils::lowerCase(dialogueId);
|
|
||||||
std::vector<int> erasedRecords;
|
std::vector<int> erasedRecords;
|
||||||
|
|
||||||
std::map<std::string, int>::const_iterator current = getIdMap().lower_bound(id);
|
Range range = getTopicRange(dialogueId); // getTopicRange converts dialogueId to lower case first
|
||||||
std::map<std::string, int>::const_iterator end = getIdMap().end();
|
|
||||||
for (; current != end; ++current)
|
for (; range.first != range.second; ++range.first)
|
||||||
{
|
{
|
||||||
Record<Info> record = getRecord(current->second);
|
const Record<Info>& record = **range.first;
|
||||||
|
|
||||||
if (Misc::StringUtils::ciEqual(dialogueId, record.get().mTopicId))
|
if (Misc::StringUtils::ciEqual(dialogueId, record.get().mTopicId))
|
||||||
{
|
{
|
||||||
if (record.mState == RecordBase::State_ModifiedOnly)
|
if (record.mState == RecordBase::State_ModifiedOnly)
|
||||||
{
|
{
|
||||||
erasedRecords.push_back(current->second);
|
erasedRecords.push_back(range.first - getRecords().begin());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
record.mState = RecordBase::State_Deleted;
|
std::unique_ptr<Record<Info> > record2(new Record<Info>(record));
|
||||||
setRecord(current->second, record);
|
record2->mState = RecordBase::State_Deleted;
|
||||||
|
setRecord(range.first - getRecords().begin(), std::move(record2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -223,3 +298,105 @@ void CSMWorld::InfoCollection::removeDialogueInfos(const std::string& dialogueId
|
|||||||
erasedRecords.pop_back();
|
erasedRecords.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: removing a record should adjust prev/next and mark those records as modified
|
||||||
|
// accordingly (also consider undo)
|
||||||
|
void CSMWorld::InfoCollection::removeRows (int index, int count)
|
||||||
|
{
|
||||||
|
Collection<Info, IdAccessor<Info> >::removeRows(index, count); // erase records only
|
||||||
|
|
||||||
|
for (std::unordered_map<std::string, std::vector<std::pair<std::string, int> > >::iterator iter
|
||||||
|
= mInfoIndex.begin(); iter != mInfoIndex.end();)
|
||||||
|
{
|
||||||
|
for (std::vector<std::pair<std::string, int> >::iterator it = iter->second.begin();
|
||||||
|
it != iter->second.end();)
|
||||||
|
{
|
||||||
|
if (it->second >= index)
|
||||||
|
{
|
||||||
|
if (it->second >= index+count)
|
||||||
|
{
|
||||||
|
it->second -= count;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
iter->second.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for an empty vector
|
||||||
|
if (iter->second.empty())
|
||||||
|
mInfoIndex.erase(iter++);
|
||||||
|
else
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::InfoCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Record<Info> > record2(new Record<Info>);
|
||||||
|
|
||||||
|
record2->mState = Record<Info>::State_ModifiedOnly;
|
||||||
|
record2->mModified.blank();
|
||||||
|
|
||||||
|
record2->get().mId = id;
|
||||||
|
|
||||||
|
insertRecord(std::move(record2), getInsertIndex(id, type, nullptr), type); // call InfoCollection::insertRecord()
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::InfoCollection::searchId(std::string_view id) const
|
||||||
|
{
|
||||||
|
std::string::size_type separator = id.find_last_of('#');
|
||||||
|
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
throw std::runtime_error("invalid info ID: " + std::string(id));
|
||||||
|
|
||||||
|
return getInfoIndex(id.substr(separator+1), id.substr(0, separator));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::InfoCollection::appendRecord (std::unique_ptr<RecordBase> record, UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int index = getInsertIndex(static_cast<Record<Info>*>(record.get())->get().mId, type, record.get());
|
||||||
|
|
||||||
|
insertRecord(std::move(record), index, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::InfoCollection::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
|
UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int size = static_cast<int>(getRecords().size());
|
||||||
|
|
||||||
|
std::string id = static_cast<Record<Info>*>(record.get())->get().mId;
|
||||||
|
std::string::size_type separator = id.find_last_of('#');
|
||||||
|
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
throw std::runtime_error("invalid info ID: " + id);
|
||||||
|
|
||||||
|
Collection<Info, IdAccessor<Info> >::insertRecord(std::move(record), index, type); // add records only
|
||||||
|
|
||||||
|
// adjust index
|
||||||
|
if (index < size-1)
|
||||||
|
{
|
||||||
|
for (std::unordered_map<std::string, std::vector<std::pair<std::string, int> > >::iterator iter
|
||||||
|
= mInfoIndex.begin(); iter != mInfoIndex.end(); ++iter)
|
||||||
|
{
|
||||||
|
for (std::vector<std::pair<std::string, int> >::iterator it = iter->second.begin();
|
||||||
|
it != iter->second.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->second >= index)
|
||||||
|
++(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get iterator for existing topic or a new topic
|
||||||
|
std::string lowerId = Misc::StringUtils::lowerCase(id);
|
||||||
|
std::pair<std::unordered_map<std::string, std::vector<std::pair<std::string, int> > >::iterator, bool> res
|
||||||
|
= mInfoIndex.insert(
|
||||||
|
std::make_pair(lowerId.substr(0, separator),
|
||||||
|
std::vector<std::pair<std::string, int> >())); // empty vector
|
||||||
|
|
||||||
|
// insert info and index
|
||||||
|
res.first->second.push_back(std::make_pair(lowerId.substr(separator+1), index));
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#ifndef CSM_WOLRD_INFOCOLLECTION_H
|
#ifndef CSM_WOLRD_INFOCOLLECTION_H
|
||||||
#define CSM_WOLRD_INFOCOLLECTION_H
|
#define CSM_WOLRD_INFOCOLLECTION_H
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "collection.hpp"
|
#include "collection.hpp"
|
||||||
#include "info.hpp"
|
#include "info.hpp"
|
||||||
|
|
||||||
@ -11,27 +14,52 @@ namespace ESM
|
|||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
template<>
|
||||||
|
void Collection<Info, IdAccessor<Info> >::removeRows (int index, int count);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Collection<Info, IdAccessor<Info> >::insertRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
int index, UniversalId::Type type);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool Collection<Info, IdAccessor<Info> >::reorderRowsImp (int baseIndex,
|
||||||
|
const std::vector<int>& newOrder);
|
||||||
|
|
||||||
class InfoCollection : public Collection<Info, IdAccessor<Info> >
|
class InfoCollection : public Collection<Info, IdAccessor<Info> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef std::vector<Record<Info> >::const_iterator RecordConstIterator;
|
typedef std::vector<std::unique_ptr<Record<Info> > >::const_iterator RecordConstIterator;
|
||||||
typedef std::pair<RecordConstIterator, RecordConstIterator> Range;
|
typedef std::pair<RecordConstIterator, RecordConstIterator> Range;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// The general strategy is to keep the records in Collection kept in order (within
|
||||||
|
// a topic group) while the index lookup maps are not ordered. It is assumed that
|
||||||
|
// each topic has a small number of infos, which allows the use of vectors for
|
||||||
|
// iterating through them without too much penalty.
|
||||||
|
//
|
||||||
|
// NOTE: topic string as well as id string are stored in lower case.
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, int> > > mInfoIndex;
|
||||||
|
|
||||||
void load (const Info& record, bool base);
|
void load (const Info& record, bool base);
|
||||||
|
|
||||||
int getInfoIndex (const std::string& id, const std::string& topic) const;
|
int getInfoIndex(std::string_view id, std::string_view topic) const;
|
||||||
///< Return index for record \a id or -1 (if not present; deleted records are considered)
|
///< Return index for record \a id or -1 (if not present; deleted records are considered)
|
||||||
///
|
///
|
||||||
/// \param id info ID without topic prefix
|
/// \param id info ID without topic prefix
|
||||||
|
//
|
||||||
|
/// \attention id and topic are assumed to be in lower case
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int getAppendIndex (const std::string& id,
|
int getInsertIndex (const std::string& id,
|
||||||
UniversalId::Type type = UniversalId::Type_None) const override;
|
UniversalId::Type type = UniversalId::Type_None,
|
||||||
|
RecordBase *record = nullptr) const override;
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
///
|
||||||
|
/// Works like getAppendIndex unless an overloaded method uses the record pointer
|
||||||
|
/// to get additional info about the record that results in an alternative index.
|
||||||
|
|
||||||
bool reorderRows (int baseIndex, const std::vector<int>& newOrder) override;
|
bool reorderRows (int baseIndex, const std::vector<int>& newOrder) override;
|
||||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||||
@ -46,6 +74,20 @@ namespace CSMWorld
|
|||||||
/// the given topic.
|
/// the given topic.
|
||||||
|
|
||||||
void removeDialogueInfos(const std::string& dialogueId);
|
void removeDialogueInfos(const std::string& dialogueId);
|
||||||
|
|
||||||
|
void removeRows (int index, int count) override;
|
||||||
|
|
||||||
|
void appendBlankRecord (const std::string& id,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None) override;
|
||||||
|
|
||||||
|
int searchId(std::string_view id) const override;
|
||||||
|
|
||||||
|
void appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None) override;
|
||||||
|
|
||||||
|
void insertRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
int index,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,23 +90,23 @@ namespace CSMWorld
|
|||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::addNestedRow(int row, int column, int position)
|
void NestedIdCollection<ESXRecordT, IdAccessorT>::addNestedRow(int row, int column, int position)
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record;
|
std::unique_ptr<Record<ESXRecordT> > record(new Record<ESXRecordT>);
|
||||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
record->assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).addRow(record, position);
|
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).addRow(*record, position);
|
||||||
|
|
||||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
Collection<ESXRecordT, IdAccessorT>::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::removeNestedRows(int row, int column, int subRow)
|
void NestedIdCollection<ESXRecordT, IdAccessorT>::removeNestedRows(int row, int column, int subRow)
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record;
|
std::unique_ptr<Record<ESXRecordT> > record(new Record<ESXRecordT>);
|
||||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
record->assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).removeRow(record, subRow);
|
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).removeRow(*record, subRow);
|
||||||
|
|
||||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
Collection<ESXRecordT, IdAccessorT>::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -121,13 +121,13 @@ namespace CSMWorld
|
|||||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedData(int row,
|
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedData(int row,
|
||||||
int column, const QVariant& data, int subRow, int subColumn)
|
int column, const QVariant& data, int subRow, int subColumn)
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record;
|
std::unique_ptr<Record<ESXRecordT> > record(new Record<ESXRecordT>);
|
||||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
record->assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setData(
|
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setData(
|
||||||
record, data, subRow, subColumn);
|
*record, data, subRow, subColumn);
|
||||||
|
|
||||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
Collection<ESXRecordT, IdAccessorT>::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
@ -142,13 +142,13 @@ namespace CSMWorld
|
|||||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedTable(int row,
|
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedTable(int row,
|
||||||
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record;
|
std::unique_ptr<Record<ESXRecordT> > record(new Record<ESXRecordT>);
|
||||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
record->assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setTable(
|
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setTable(
|
||||||
record, nestedTable);
|
*record, nestedTable);
|
||||||
|
|
||||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
Collection<ESXRecordT, IdAccessorT>::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
@ -35,22 +35,22 @@ namespace CSMWorld
|
|||||||
|
|
||||||
void NestedInfoCollection::addNestedRow(int row, int column, int position)
|
void NestedInfoCollection::addNestedRow(int row, int column, int position)
|
||||||
{
|
{
|
||||||
Record<Info> record;
|
std::unique_ptr<Record<Info> > record(new Record<Info>);
|
||||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
record->assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).addRow(record, position);
|
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).addRow(*record, position);
|
||||||
|
|
||||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
Collection<Info, IdAccessor<Info> >::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NestedInfoCollection::removeNestedRows(int row, int column, int subRow)
|
void NestedInfoCollection::removeNestedRows(int row, int column, int subRow)
|
||||||
{
|
{
|
||||||
Record<Info> record;
|
std::unique_ptr<Record<Info> > record(new Record<Info>);
|
||||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
record->assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).removeRow(record, subRow);
|
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).removeRow(*record, subRow);
|
||||||
|
|
||||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
Collection<Info, IdAccessor<Info> >::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant NestedInfoCollection::getNestedData (int row,
|
QVariant NestedInfoCollection::getNestedData (int row,
|
||||||
@ -63,13 +63,13 @@ namespace CSMWorld
|
|||||||
void NestedInfoCollection::setNestedData(int row,
|
void NestedInfoCollection::setNestedData(int row,
|
||||||
int column, const QVariant& data, int subRow, int subColumn)
|
int column, const QVariant& data, int subRow, int subColumn)
|
||||||
{
|
{
|
||||||
Record<Info> record;
|
std::unique_ptr<Record<Info> > record(new Record<Info>);
|
||||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
record->assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setData(
|
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setData(
|
||||||
record, data, subRow, subColumn);
|
*record, data, subRow, subColumn);
|
||||||
|
|
||||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
Collection<Info, IdAccessor<Info> >::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::NestedTableWrapperBase* NestedInfoCollection::nestedTable(int row,
|
CSMWorld::NestedTableWrapperBase* NestedInfoCollection::nestedTable(int row,
|
||||||
@ -82,13 +82,13 @@ namespace CSMWorld
|
|||||||
void NestedInfoCollection::setNestedTable(int row,
|
void NestedInfoCollection::setNestedTable(int row,
|
||||||
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
||||||
{
|
{
|
||||||
Record<Info> record;
|
std::unique_ptr<Record<Info> > record(new Record<Info>);
|
||||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
record->assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||||
|
|
||||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setTable(
|
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setTable(
|
||||||
record, nestedTable);
|
*record, nestedTable);
|
||||||
|
|
||||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
Collection<Info, IdAccessor<Info> >::setRecord(row, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
int NestedInfoCollection::getNestedRowsCount(int row, int column) const
|
int NestedInfoCollection::getNestedRowsCount(int row, int column) const
|
||||||
|
@ -20,7 +20,7 @@ namespace CSMWorld
|
|||||||
{
|
{
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
|
||||||
void load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection<Cell>& cells);
|
void load (ESM::ESMReader &esm, bool &isDeleted, const IdCollection<Cell, IdAccessor<Cell> >& cells);
|
||||||
void load (ESM::ESMReader &esm, bool &isDeleted);
|
void load (ESM::ESMReader &esm, bool &isDeleted);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef CSM_WOLRD_RECORD_H
|
#ifndef CSM_WOLRD_RECORD_H
|
||||||
#define CSM_WOLRD_RECORD_H
|
#define CSM_WOLRD_RECORD_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
@ -20,9 +21,9 @@ namespace CSMWorld
|
|||||||
|
|
||||||
virtual ~RecordBase();
|
virtual ~RecordBase();
|
||||||
|
|
||||||
virtual RecordBase *clone() const = 0;
|
virtual std::unique_ptr<RecordBase> clone() const = 0;
|
||||||
|
|
||||||
virtual RecordBase *modifiedCopy() const = 0;
|
virtual std::unique_ptr<RecordBase> modifiedCopy() const = 0;
|
||||||
|
|
||||||
virtual void assign (const RecordBase& record) = 0;
|
virtual void assign (const RecordBase& record) = 0;
|
||||||
///< Will throw an exception if the types don't match.
|
///< Will throw an exception if the types don't match.
|
||||||
@ -45,9 +46,9 @@ namespace CSMWorld
|
|||||||
Record(State state,
|
Record(State state,
|
||||||
const ESXRecordT *base = 0, const ESXRecordT *modified = 0);
|
const ESXRecordT *base = 0, const ESXRecordT *modified = 0);
|
||||||
|
|
||||||
RecordBase *clone() const override;
|
std::unique_ptr<RecordBase> clone() const override;
|
||||||
|
|
||||||
RecordBase *modifiedCopy() const override;
|
std::unique_ptr<RecordBase> modifiedCopy() const override;
|
||||||
|
|
||||||
void assign (const RecordBase& record) override;
|
void assign (const RecordBase& record) override;
|
||||||
|
|
||||||
@ -85,15 +86,16 @@ namespace CSMWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ESXRecordT>
|
template <typename ESXRecordT>
|
||||||
RecordBase *Record<ESXRecordT>::modifiedCopy() const
|
std::unique_ptr<RecordBase> Record<ESXRecordT>::modifiedCopy() const
|
||||||
{
|
{
|
||||||
return new Record<ESXRecordT> (State_ModifiedOnly, nullptr, &(this->get()));
|
return std::make_unique<Record<ESXRecordT> >(
|
||||||
|
Record<ESXRecordT>(State_ModifiedOnly, nullptr, &(this->get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ESXRecordT>
|
template <typename ESXRecordT>
|
||||||
RecordBase *Record<ESXRecordT>::clone() const
|
std::unique_ptr<RecordBase> Record<ESXRecordT>::clone() const
|
||||||
{
|
{
|
||||||
return new Record<ESXRecordT> (*this);
|
return std::make_unique<Record<ESXRecordT> >(Record<ESXRecordT>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ESXRecordT>
|
template <typename ESXRecordT>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "cellcoordinates.hpp"
|
#include "cellcoordinates.hpp"
|
||||||
|
|
||||||
CSMWorld::CellRef::CellRef() : mNew (true)
|
CSMWorld::CellRef::CellRef() : mNew (true), mIdNum(0)
|
||||||
{
|
{
|
||||||
mRefNum.mIndex = 0;
|
mRefNum.mIndex = 0;
|
||||||
mRefNum.mContentFile = 0;
|
mRefNum.mContentFile = 0;
|
||||||
|
@ -14,6 +14,7 @@ namespace CSMWorld
|
|||||||
std::string mCell;
|
std::string mCell;
|
||||||
std::string mOriginalCell;
|
std::string mOriginalCell;
|
||||||
bool mNew; // new reference, not counted yet, ref num not assigned yet
|
bool mNew; // new reference, not counted yet, ref num not assigned yet
|
||||||
|
unsigned int mIdNum;
|
||||||
|
|
||||||
CellRef();
|
CellRef();
|
||||||
|
|
||||||
|
@ -7,8 +7,39 @@
|
|||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
#include "record.hpp"
|
#include "record.hpp"
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
void Collection<CellRef, IdAccessor<CellRef> >::removeRows (int index, int count)
|
||||||
|
{
|
||||||
|
mRecords.erase(mRecords.begin()+index, mRecords.begin()+index+count);
|
||||||
|
|
||||||
|
// index map is updated in RefCollection::removeRows()
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Collection<CellRef, IdAccessor<CellRef> >::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
|
UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int size = static_cast<int>(mRecords.size());
|
||||||
|
if (index < 0 || index > size)
|
||||||
|
throw std::runtime_error("index out of range");
|
||||||
|
|
||||||
|
std::unique_ptr<Record<CellRef> > record2(static_cast<Record<CellRef>*>(record.release()));
|
||||||
|
|
||||||
|
if (index == size)
|
||||||
|
mRecords.push_back(std::move(record2));
|
||||||
|
else
|
||||||
|
mRecords.insert(mRecords.begin()+index, std::move(record2));
|
||||||
|
|
||||||
|
// index map is updated in RefCollection::insertRecord()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base,
|
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base,
|
||||||
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Messages& messages)
|
std::map<unsigned int, unsigned int>& cache, CSMDoc::Messages& messages)
|
||||||
{
|
{
|
||||||
Record<Cell> cell = mCells.getRecord (cellIndex);
|
Record<Cell> cell = mCells.getRecord (cellIndex);
|
||||||
|
|
||||||
@ -19,8 +50,9 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
ESM::MovedCellRef mref;
|
ESM::MovedCellRef mref;
|
||||||
mref.mRefNum.mIndex = 0;
|
mref.mRefNum.mIndex = 0;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
bool isMoved = false;
|
||||||
|
|
||||||
while (ESM::Cell::getNextRef(reader, ref, isDeleted, true, &mref))
|
while (ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved))
|
||||||
{
|
{
|
||||||
// Keep mOriginalCell empty when in modified (as an indicator that the
|
// Keep mOriginalCell empty when in modified (as an indicator that the
|
||||||
// original cell will always be equal the current cell).
|
// original cell will always be equal the current cell).
|
||||||
@ -34,7 +66,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
ref.mCell = "#" + std::to_string(index.first) + " " + std::to_string(index.second);
|
ref.mCell = "#" + std::to_string(index.first) + " " + std::to_string(index.second);
|
||||||
|
|
||||||
// Handle non-base moved references
|
// Handle non-base moved references
|
||||||
if (!base && mref.mRefNum.mIndex != 0)
|
if (!base && isMoved)
|
||||||
{
|
{
|
||||||
// Moved references must have a link back to their original cell
|
// Moved references must have a link back to their original cell
|
||||||
// See discussion: https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30
|
// See discussion: https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30
|
||||||
@ -59,17 +91,47 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
else
|
else
|
||||||
ref.mCell = cell2.mId;
|
ref.mCell = cell2.mId;
|
||||||
|
|
||||||
mref.mRefNum.mIndex = 0;
|
if (ref.mRefNum.mContentFile != -1 && !base)
|
||||||
|
|
||||||
// ignore content file number
|
|
||||||
std::map<ESM::RefNum, std::string>::iterator iter = cache.begin();
|
|
||||||
unsigned int thisIndex = ref.mRefNum.mIndex & 0x00ffffff;
|
|
||||||
if (ref.mRefNum.mContentFile != -1 && !base) ref.mRefNum.mContentFile = ref.mRefNum.mIndex >> 24;
|
|
||||||
|
|
||||||
for (; iter != cache.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
if (thisIndex == iter->first.mIndex)
|
ref.mRefNum.mContentFile = ref.mRefNum.mIndex >> 24;
|
||||||
break;
|
ref.mRefNum.mIndex &= 0x00ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int refNum = (ref.mRefNum.mIndex & 0x00ffffff) |
|
||||||
|
(ref.mRefNum.hasContentFile() ? ref.mRefNum.mContentFile : 0xff) << 24;
|
||||||
|
|
||||||
|
std::map<unsigned int, unsigned int>::iterator iter = cache.find(refNum);
|
||||||
|
|
||||||
|
if (isMoved)
|
||||||
|
{
|
||||||
|
if (iter == cache.end())
|
||||||
|
{
|
||||||
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Cell,
|
||||||
|
mCells.getId(cellIndex));
|
||||||
|
|
||||||
|
messages.add(id, "Attempt to move a non-existent reference - RefNum index "
|
||||||
|
+ std::to_string(ref.mRefNum.mIndex) + ", refID " + ref.mRefID + ", content file index "
|
||||||
|
+ std::to_string(ref.mRefNum.mContentFile),
|
||||||
|
/*hint*/"",
|
||||||
|
CSMDoc::Message::Severity_Warning);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = getIntIndex(iter->second);
|
||||||
|
|
||||||
|
// ensure we have the same record id for setRecord()
|
||||||
|
ref.mId = getRecord(index).get().mId;
|
||||||
|
ref.mIdNum = extractIdNum(ref.mId);
|
||||||
|
|
||||||
|
std::unique_ptr<Record<CellRef> > record(new Record<CellRef>);
|
||||||
|
// TODO: check whether a base record be moved
|
||||||
|
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
|
(base ? record->mBase : record->mModified) = std::move(ref);
|
||||||
|
|
||||||
|
// overwrite original record
|
||||||
|
setRecord(index, std::move(record));
|
||||||
|
|
||||||
|
continue; // NOTE: assumed moved references are not deleted at the same time
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDeleted)
|
if (isDeleted)
|
||||||
@ -79,13 +141,15 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
|
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
|
||||||
mCells.getId (cellIndex));
|
mCells.getId (cellIndex));
|
||||||
|
|
||||||
messages.add (id, "Attempt to delete a non-existent reference");
|
messages.add (id, "Attempt to delete a non-existent reference - RefNum index "
|
||||||
|
+ std::to_string(ref.mRefNum.mIndex) + ", refID " + ref.mRefID + ", content file index "
|
||||||
|
+ std::to_string(ref.mRefNum.mContentFile),
|
||||||
|
/*hint*/"",
|
||||||
|
CSMDoc::Message::Severity_Warning);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = getIndex (iter->second);
|
int index = getIntIndex (iter->second);
|
||||||
|
|
||||||
Record<CellRef> record = getRecord (index);
|
|
||||||
|
|
||||||
if (base)
|
if (base)
|
||||||
{
|
{
|
||||||
@ -94,8 +158,9 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
record.mState = RecordBase::State_Deleted;
|
std::unique_ptr<Record<CellRef> > record(new Record<CellRef>(getRecord(index)));
|
||||||
setRecord (index, record);
|
record->mState = RecordBase::State_Deleted;
|
||||||
|
setRecord(index, std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -104,30 +169,47 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||||||
if (iter==cache.end())
|
if (iter==cache.end())
|
||||||
{
|
{
|
||||||
// new reference
|
// new reference
|
||||||
|
ref.mIdNum = mNextId; // FIXME: fragile
|
||||||
ref.mId = getNewId();
|
ref.mId = getNewId();
|
||||||
|
|
||||||
Record<CellRef> record;
|
cache.emplace(refNum, ref.mIdNum);
|
||||||
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
|
||||||
const ESM::RefNum refNum = ref.mRefNum;
|
|
||||||
std::string refId = ref.mId;
|
|
||||||
(base ? record.mBase : record.mModified) = std::move(ref);
|
|
||||||
|
|
||||||
appendRecord (record);
|
std::unique_ptr<Record<CellRef> > record(new Record<CellRef>);
|
||||||
|
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
|
(base ? record->mBase : record->mModified) = std::move(ref);
|
||||||
|
|
||||||
cache.emplace(refNum, std::move(refId));
|
appendRecord(std::move(record));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// old reference -> merge
|
// old reference -> merge
|
||||||
ref.mId = iter->second;
|
int index = getIntIndex(iter->second);
|
||||||
|
#if 0
|
||||||
|
// ref.mRefNum.mIndex : the key
|
||||||
|
// iter->second : previously cached idNum for the key
|
||||||
|
// index : position of the record for that idNum
|
||||||
|
// getRecord(index).get() : record in the index position
|
||||||
|
assert(iter->second != getRecord(index).get().mIdNum); // sanity check
|
||||||
|
|
||||||
int index = getIndex (ref.mId);
|
// check if the plugin used the same RefNum index for a different record
|
||||||
|
if (ref.mRefID != getRecord(index).get().mRefID)
|
||||||
|
{
|
||||||
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Cell, mCells.getId(cellIndex));
|
||||||
|
messages.add(id,
|
||||||
|
"RefNum renamed from RefID \"" + getRecord(index).get().mRefID + "\" to \""
|
||||||
|
+ ref.mRefID + "\" (RefNum index " + std::to_string(ref.mRefNum.mIndex) + ")",
|
||||||
|
/*hint*/"",
|
||||||
|
CSMDoc::Message::Severity_Info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ref.mId = getRecord(index).get().mId;
|
||||||
|
ref.mIdNum = extractIdNum(ref.mId);
|
||||||
|
|
||||||
Record<CellRef> record = getRecord (index);
|
std::unique_ptr<Record<CellRef> > record(new Record<CellRef>(getRecord(index)));
|
||||||
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified;
|
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified;
|
||||||
(base ? record.mBase : record.mModified) = std::move(ref);
|
(base ? record->mBase : record->mModified) = std::move(ref);
|
||||||
|
|
||||||
setRecord (index, record);
|
setRecord(index, std::move(record));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,3 +218,117 @@ std::string CSMWorld::RefCollection::getNewId()
|
|||||||
{
|
{
|
||||||
return "ref#" + std::to_string(mNextId++);
|
return "ref#" + std::to_string(mNextId++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int CSMWorld::RefCollection::extractIdNum(std::string_view id) const
|
||||||
|
{
|
||||||
|
std::string::size_type separator = id.find_last_of('#');
|
||||||
|
|
||||||
|
if (separator == std::string::npos)
|
||||||
|
throw std::runtime_error("invalid ref ID: " + std::string(id));
|
||||||
|
|
||||||
|
return static_cast<unsigned int>(std::stoi(std::string(id.substr(separator+1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::RefCollection::getIntIndex (unsigned int id) const
|
||||||
|
{
|
||||||
|
int index = searchId(id);
|
||||||
|
|
||||||
|
if (index == -1)
|
||||||
|
throw std::runtime_error("invalid RefNum: " + std::to_string(id));
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::RefCollection::searchId (unsigned int id) const
|
||||||
|
{
|
||||||
|
std::map<unsigned int, int>::const_iterator iter = mRefIndex.find(id);
|
||||||
|
|
||||||
|
if (iter == mRefIndex.end())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::removeRows (int index, int count)
|
||||||
|
{
|
||||||
|
Collection<CellRef, IdAccessor<CellRef> >::removeRows(index, count); // erase records only
|
||||||
|
|
||||||
|
std::map<unsigned int, int>::iterator iter = mRefIndex.begin();
|
||||||
|
while (iter != mRefIndex.end())
|
||||||
|
{
|
||||||
|
if (iter->second>=index)
|
||||||
|
{
|
||||||
|
if (iter->second >= index+count)
|
||||||
|
{
|
||||||
|
iter->second -= count;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mRefIndex.erase(iter++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Record<CellRef> > record(new Record<CellRef>);
|
||||||
|
|
||||||
|
record->mState = Record<CellRef>::State_ModifiedOnly;
|
||||||
|
record->mModified.blank();
|
||||||
|
|
||||||
|
record->get().mId = id;
|
||||||
|
record->get().mIdNum = extractIdNum(id);
|
||||||
|
|
||||||
|
Collection<CellRef, IdAccessor<CellRef> >::appendRecord(std::move(record));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::cloneRecord (const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Record<CellRef> > copy(new Record<CellRef>);
|
||||||
|
|
||||||
|
copy->mModified = getRecord(origin).get();
|
||||||
|
copy->mState = RecordBase::State_ModifiedOnly;
|
||||||
|
|
||||||
|
copy->get().mId = destination;
|
||||||
|
copy->get().mIdNum = extractIdNum(destination);
|
||||||
|
|
||||||
|
insertRecord(std::move(copy), getAppendIndex(destination, type)); // call RefCollection::insertRecord()
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::RefCollection::searchId(std::string_view id) const
|
||||||
|
{
|
||||||
|
return searchId(extractIdNum(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::appendRecord (std::unique_ptr<RecordBase> record, UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int index = getAppendIndex(/*id*/"", type); // for CellRef records id is ignored
|
||||||
|
|
||||||
|
mRefIndex.insert(std::make_pair(static_cast<Record<CellRef>*>(record.get())->get().mIdNum, index));
|
||||||
|
|
||||||
|
Collection<CellRef, IdAccessor<CellRef> >::insertRecord(std::move(record), index, type); // add records only
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
|
UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int size = getAppendIndex(/*id*/"", type); // for CellRef records id is ignored
|
||||||
|
unsigned int idNum = static_cast<Record<CellRef>*>(record.get())->get().mIdNum;
|
||||||
|
|
||||||
|
Collection<CellRef, IdAccessor<CellRef> >::insertRecord(std::move(record), index, type); // add records only
|
||||||
|
|
||||||
|
if (index < size-1)
|
||||||
|
{
|
||||||
|
for (std::map<unsigned int, int>::iterator iter(mRefIndex.begin()); iter != mRefIndex.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->second >= index)
|
||||||
|
++(iter->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mRefIndex.insert(std::make_pair(idNum, index));
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define CSM_WOLRD_REFCOLLECTION_H
|
#define CSM_WOLRD_REFCOLLECTION_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "../doc/stage.hpp"
|
#include "../doc/stage.hpp"
|
||||||
|
|
||||||
@ -14,12 +15,27 @@ namespace CSMWorld
|
|||||||
struct Cell;
|
struct Cell;
|
||||||
class UniversalId;
|
class UniversalId;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Collection<CellRef, IdAccessor<CellRef> >::removeRows (int index, int count);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Collection<CellRef, IdAccessor<CellRef> >::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
||||||
|
UniversalId::Type type);
|
||||||
|
|
||||||
/// \brief References in cells
|
/// \brief References in cells
|
||||||
class RefCollection : public Collection<CellRef>
|
class RefCollection : public Collection<CellRef>
|
||||||
{
|
{
|
||||||
Collection<Cell>& mCells;
|
Collection<Cell>& mCells;
|
||||||
|
std::map<unsigned int, int> mRefIndex; // CellRef index keyed by CSMWorld::CellRef::mIdNum
|
||||||
|
|
||||||
int mNextId;
|
int mNextId;
|
||||||
|
|
||||||
|
unsigned int extractIdNum(std::string_view id) const;
|
||||||
|
|
||||||
|
int getIntIndex (unsigned int id) const;
|
||||||
|
|
||||||
|
int searchId (unsigned int id) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// MSVC needs the constructor for a class inheriting a template to be defined in header
|
// MSVC needs the constructor for a class inheriting a template to be defined in header
|
||||||
RefCollection (Collection<Cell>& cells)
|
RefCollection (Collection<Cell>& cells)
|
||||||
@ -27,10 +43,28 @@ namespace CSMWorld
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
void load (ESM::ESMReader& reader, int cellIndex, bool base,
|
void load (ESM::ESMReader& reader, int cellIndex, bool base,
|
||||||
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Messages& messages);
|
std::map<unsigned int, unsigned int>& cache, CSMDoc::Messages& messages);
|
||||||
///< Load a sequence of references.
|
///< Load a sequence of references.
|
||||||
|
|
||||||
std::string getNewId();
|
std::string getNewId();
|
||||||
|
|
||||||
|
virtual void removeRows (int index, int count);
|
||||||
|
|
||||||
|
virtual void appendBlankRecord (const std::string& id,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
|
|
||||||
|
virtual void cloneRecord (const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type);
|
||||||
|
|
||||||
|
virtual int searchId(std::string_view id) const;
|
||||||
|
|
||||||
|
virtual void appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
|
|
||||||
|
virtual void insertRecord (std::unique_ptr<RecordBase> record,
|
||||||
|
int index,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ namespace CSMWorld
|
|||||||
const RefIdColumn *mId;
|
const RefIdColumn *mId;
|
||||||
const RefIdColumn *mModified;
|
const RefIdColumn *mModified;
|
||||||
const RefIdColumn *mType;
|
const RefIdColumn *mType;
|
||||||
|
const RefIdColumn *mBlocked;
|
||||||
|
|
||||||
|
BaseColumns () : mBlocked(nullptr) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Base adapter for all refereceable record types
|
/// \brief Base adapter for all refereceable record types
|
||||||
@ -90,6 +93,9 @@ namespace CSMWorld
|
|||||||
if (column==mBase.mType)
|
if (column==mBase.mType)
|
||||||
return static_cast<int> (mType);
|
return static_cast<int> (mType);
|
||||||
|
|
||||||
|
if (column==mBase.mBlocked)
|
||||||
|
return (record.get().mRecordFlags & ESM::FLAG_Blocked) != 0;
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +108,17 @@ namespace CSMWorld
|
|||||||
|
|
||||||
if (column==mBase.mModified)
|
if (column==mBase.mModified)
|
||||||
record.mState = static_cast<RecordBase::State> (value.toInt());
|
record.mState = static_cast<RecordBase::State> (value.toInt());
|
||||||
|
else if (column==mBase.mBlocked)
|
||||||
|
{
|
||||||
|
RecordT record2 = record.get();
|
||||||
|
|
||||||
|
if (value.toInt() != 0)
|
||||||
|
record2.mRecordFlags |= ESM::FLAG_Blocked;
|
||||||
|
else
|
||||||
|
record2.mRecordFlags &= ~ESM::FLAG_Blocked;
|
||||||
|
|
||||||
|
record.setModified(record2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
@ -110,6 +127,14 @@ namespace CSMWorld
|
|||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Body Part should not have persistence (but BodyPart is not listed in the Objects
|
||||||
|
// table at the moment).
|
||||||
|
//
|
||||||
|
// Spellmaking - not persistent - currently not part of objects table
|
||||||
|
// Enchanting - not persistent - currently not part of objects table
|
||||||
|
//
|
||||||
|
// Leveled Creature - no model, so not persistent
|
||||||
|
// Leveled Item - no model, so not persistent
|
||||||
|
|
||||||
struct ModelColumns : public BaseColumns
|
struct ModelColumns : public BaseColumns
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
@ -49,17 +50,22 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||||||
mColumns.emplace_back(Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
|
mColumns.emplace_back(Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
|
||||||
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
|
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false);
|
||||||
baseColumns.mType = &mColumns.back();
|
baseColumns.mType = &mColumns.back();
|
||||||
|
mColumns.emplace_back(Columns::ColumnId_Blocked, ColumnBase::Display_Boolean,
|
||||||
|
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh);
|
||||||
|
baseColumns.mBlocked = &mColumns.back();
|
||||||
|
|
||||||
ModelColumns modelColumns (baseColumns);
|
ModelColumns modelColumns (baseColumns);
|
||||||
|
|
||||||
mColumns.emplace_back(Columns::ColumnId_Model, ColumnBase::Display_Mesh);
|
|
||||||
modelColumns.mModel = &mColumns.back();
|
|
||||||
mColumns.emplace_back(Columns::ColumnId_Persistent, ColumnBase::Display_Boolean);
|
mColumns.emplace_back(Columns::ColumnId_Persistent, ColumnBase::Display_Boolean);
|
||||||
modelColumns.mPersistence = &mColumns.back();
|
modelColumns.mPersistence = &mColumns.back();
|
||||||
|
mColumns.emplace_back(Columns::ColumnId_Model, ColumnBase::Display_Mesh);
|
||||||
|
modelColumns.mModel = &mColumns.back();
|
||||||
|
|
||||||
NameColumns nameColumns (modelColumns);
|
NameColumns nameColumns (modelColumns);
|
||||||
|
|
||||||
mColumns.emplace_back(Columns::ColumnId_Name, ColumnBase::Display_String);
|
// Only items that can be placed in a container have the 32 character limit, but enforce
|
||||||
|
// that for all referenceable types for now.
|
||||||
|
mColumns.emplace_back(Columns::ColumnId_Name, ColumnBase::Display_String32);
|
||||||
nameColumns.mName = &mColumns.back();
|
nameColumns.mName = &mColumns.back();
|
||||||
mColumns.emplace_back(Columns::ColumnId_Script, ColumnBase::Display_Script);
|
mColumns.emplace_back(Columns::ColumnId_Script, ColumnBase::Display_Script);
|
||||||
nameColumns.mScript = &mColumns.back();
|
nameColumns.mScript = &mColumns.back();
|
||||||
@ -231,9 +237,9 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String));
|
new RefIdColumn (Columns::ColumnId_AiActivateName, CSMWorld::ColumnBase::Display_String32));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiTargetId, CSMWorld::ColumnBase::Display_String));
|
new RefIdColumn (Columns::ColumnId_AiTargetId, CSMWorld::ColumnBase::Display_String32));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
new RefIdColumn (Columns::ColumnId_AiTargetCell, CSMWorld::ColumnBase::Display_String));
|
new RefIdColumn (Columns::ColumnId_AiTargetCell, CSMWorld::ColumnBase::Display_String));
|
||||||
mColumns.back().addColumn(
|
mColumns.back().addColumn(
|
||||||
@ -479,6 +485,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||||||
mColumns.emplace_back(Columns::ColumnId_Class, ColumnBase::Display_Class);
|
mColumns.emplace_back(Columns::ColumnId_Class, ColumnBase::Display_Class);
|
||||||
npcColumns.mClass = &mColumns.back();
|
npcColumns.mClass = &mColumns.back();
|
||||||
|
|
||||||
|
// NAME32 enforced in IdCompletionDelegate::createEditor()
|
||||||
mColumns.emplace_back(Columns::ColumnId_Faction, ColumnBase::Display_Faction);
|
mColumns.emplace_back(Columns::ColumnId_Faction, ColumnBase::Display_Faction);
|
||||||
npcColumns.mFaction = &mColumns.back();
|
npcColumns.mFaction = &mColumns.back();
|
||||||
|
|
||||||
@ -764,7 +771,6 @@ void CSMWorld::RefIdCollection::setNestedData(int row, int column, const QVarian
|
|||||||
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
||||||
|
|
||||||
nestedAdapter.setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn);
|
nestedAdapter.setNestedData(&mColumns.at (column), mData, localIndex.first, data, subRow, subColumn);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::removeRows (int index, int count)
|
void CSMWorld::RefIdCollection::removeRows (int index, int count)
|
||||||
@ -778,7 +784,6 @@ void CSMWorld::RefIdCollection::removeNestedRows(int row, int column, int subRow
|
|||||||
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
||||||
|
|
||||||
nestedAdapter.removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow);
|
nestedAdapter.removeNestedRow(&mColumns.at (column), mData, localIndex.first, subRow);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
|
||||||
@ -786,7 +791,7 @@ void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, Univer
|
|||||||
mData.appendRecord (type, id, false);
|
mData.appendRecord (type, id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::RefIdCollection::searchId (const std::string& id) const
|
int CSMWorld::RefIdCollection::searchId(std::string_view id) const
|
||||||
{
|
{
|
||||||
RefIdData::LocalIndex localIndex = mData.searchId (id);
|
RefIdData::LocalIndex localIndex = mData.searchId (id);
|
||||||
|
|
||||||
@ -796,18 +801,18 @@ int CSMWorld::RefIdCollection::searchId (const std::string& id) const
|
|||||||
return mData.localToGlobalIndex (localIndex);
|
return mData.localToGlobalIndex (localIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
|
void CSMWorld::RefIdCollection::replace (int index, std::unique_ptr<RecordBase> record)
|
||||||
{
|
{
|
||||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
mData.getRecord (mData.globalToLocalIndex (index)).assign (*record.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
||||||
const std::string& destination,
|
const std::string& destination,
|
||||||
const CSMWorld::UniversalId::Type type)
|
const CSMWorld::UniversalId::Type type)
|
||||||
{
|
{
|
||||||
std::unique_ptr<RecordBase> newRecord(mData.getRecord(mData.searchId(origin)).modifiedCopy());
|
std::unique_ptr<RecordBase> newRecord = mData.getRecord(mData.searchId(origin)).modifiedCopy();
|
||||||
mAdapters.find(type)->second->setId(*newRecord, destination);
|
mAdapters.find(type)->second->setId(*newRecord, destination);
|
||||||
mData.insertRecord(*newRecord, type, destination);
|
mData.insertRecord(std::move(newRecord), type, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSMWorld::RefIdCollection::touchRecord(const std::string& id)
|
bool CSMWorld::RefIdCollection::touchRecord(const std::string& id)
|
||||||
@ -816,16 +821,16 @@ bool CSMWorld::RefIdCollection::touchRecord(const std::string& id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
void CSMWorld::RefIdCollection::appendRecord (std::unique_ptr<RecordBase> record,
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
std::string id = findAdapter (type).getId (record);
|
std::string id = findAdapter (type).getId (*record.get());
|
||||||
|
|
||||||
int index = mData.getAppendIndex (type);
|
int index = mData.getAppendIndex (type);
|
||||||
|
|
||||||
mData.appendRecord (type, id, false);
|
mData.appendRecord (type, id, false);
|
||||||
|
|
||||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
mData.getRecord (mData.globalToLocalIndex (index)).assign (*record.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (const std::string& id) const
|
const CSMWorld::RecordBase& CSMWorld::RefIdCollection::getRecord (const std::string& id) const
|
||||||
@ -895,7 +900,6 @@ void CSMWorld::RefIdCollection::addNestedRow(int row, int col, int position)
|
|||||||
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second);
|
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(col), localIndex.second);
|
||||||
|
|
||||||
nestedAdapter.addNestedRow(&mColumns.at(col), mData, localIndex.first, position);
|
nestedAdapter.addNestedRow(&mColumns.at(col), mData, localIndex.first, position);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
||||||
@ -904,7 +908,6 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor
|
|||||||
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
const CSMWorld::NestedRefIdAdapterBase& nestedAdapter = getNestedAdapter(mColumns.at(column), localIndex.second);
|
||||||
|
|
||||||
nestedAdapter.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable);
|
nestedAdapter.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const
|
CSMWorld::NestedTableWrapperBase* CSMWorld::RefIdCollection::nestedTable(int row, int column) const
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "columnbase.hpp"
|
#include "columnbase.hpp"
|
||||||
#include "collectionbase.hpp"
|
#include "collectionbase.hpp"
|
||||||
@ -85,16 +86,16 @@ namespace CSMWorld
|
|||||||
void appendBlankRecord (const std::string& id, UniversalId::Type type) override;
|
void appendBlankRecord (const std::string& id, UniversalId::Type type) override;
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
int searchId (const std::string& id) const override;
|
int searchId(std::string_view id) const override;
|
||||||
////< Search record with \a id.
|
////< Search record with \a id.
|
||||||
/// \return index of record (if found) or -1 (not found)
|
/// \return index of record (if found) or -1 (not found)
|
||||||
|
|
||||||
void replace (int index, const RecordBase& record) override;
|
void replace (int index, std::unique_ptr<RecordBase> record) override;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
///
|
///
|
||||||
/// \attention \a record must not change the ID.
|
/// \attention \a record must not change the ID.
|
||||||
|
|
||||||
void appendRecord (const RecordBase& record, UniversalId::Type type) override;
|
void appendRecord (std::unique_ptr<RecordBase> record, UniversalId::Type type) override;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
///
|
///
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {}
|
CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {}
|
||||||
|
|
||||||
@ -74,8 +75,7 @@ int CSMWorld::RefIdData::localToGlobalIndex (const LocalIndex& index)
|
|||||||
return globalIndex;
|
return globalIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId (
|
CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId(std::string_view id) const
|
||||||
const std::string& id) const
|
|
||||||
{
|
{
|
||||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati
|
|||||||
return mStatics;
|
return mStatics;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
|
void CSMWorld::RefIdData::insertRecord (std::unique_ptr<CSMWorld::RecordBase> record, CSMWorld::UniversalId::Type type, const std::string& id)
|
||||||
{
|
{
|
||||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||||
mRecordContainers.find (type);
|
mRecordContainers.find (type);
|
||||||
@ -408,7 +408,7 @@ void CSMWorld::RefIdData::insertRecord (CSMWorld::RecordBase& record, CSMWorld::
|
|||||||
if (iter==mRecordContainers.end())
|
if (iter==mRecordContainers.end())
|
||||||
throw std::logic_error ("invalid local index type");
|
throw std::logic_error ("invalid local index type");
|
||||||
|
|
||||||
iter->second->insertRecord(record);
|
iter->second->insertRecord(std::move(record));
|
||||||
|
|
||||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||||
LocalIndex (iter->second->getSize()-1, type)));
|
LocalIndex (iter->second->getSize()-1, type)));
|
||||||
@ -420,9 +420,7 @@ void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const
|
|||||||
|
|
||||||
RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second;
|
RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second;
|
||||||
|
|
||||||
std::string id = source->getId (localIndex.first);
|
target.insertRecord(source->getRecord(localIndex.first).modifiedCopy(),
|
||||||
|
localIndex.second,
|
||||||
std::unique_ptr<CSMWorld::RecordBase> newRecord (source->getRecord (localIndex.first).modifiedCopy());
|
source->getId(localIndex.first));
|
||||||
|
|
||||||
target.insertRecord (*newRecord, localIndex.second, id);
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <cassert>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <components/esm/loadacti.hpp>
|
#include <components/esm/loadacti.hpp>
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
@ -51,7 +54,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
virtual void appendRecord (const std::string& id, bool base) = 0;
|
virtual void appendRecord (const std::string& id, bool base) = 0;
|
||||||
|
|
||||||
virtual void insertRecord (RecordBase& record) = 0;
|
virtual void insertRecord (std::unique_ptr<RecordBase> record) = 0;
|
||||||
|
|
||||||
virtual int load (ESM::ESMReader& reader, bool base) = 0;
|
virtual int load (ESM::ESMReader& reader, bool base) = 0;
|
||||||
///< \return index of a loaded record or -1 if no record was loaded
|
///< \return index of a loaded record or -1 if no record was loaded
|
||||||
@ -66,7 +69,7 @@ namespace CSMWorld
|
|||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
struct RefIdDataContainer : public RefIdDataContainerBase
|
struct RefIdDataContainer : public RefIdDataContainerBase
|
||||||
{
|
{
|
||||||
std::vector<Record<RecordT> > mContainer;
|
std::vector<std::unique_ptr<Record<RecordT> > > mContainer;
|
||||||
|
|
||||||
int getSize() const override;
|
int getSize() const override;
|
||||||
|
|
||||||
@ -78,7 +81,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
void appendRecord (const std::string& id, bool base) override;
|
void appendRecord (const std::string& id, bool base) override;
|
||||||
|
|
||||||
void insertRecord (RecordBase& record) override;
|
void insertRecord (std::unique_ptr<RecordBase> record) override;
|
||||||
|
|
||||||
int load (ESM::ESMReader& reader, bool base) override;
|
int load (ESM::ESMReader& reader, bool base) override;
|
||||||
///< \return index of a loaded record or -1 if no record was loaded
|
///< \return index of a loaded record or -1 if no record was loaded
|
||||||
@ -91,10 +94,13 @@ namespace CSMWorld
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
void RefIdDataContainer<RecordT>::insertRecord(RecordBase& record)
|
void RefIdDataContainer<RecordT>::insertRecord(std::unique_ptr<RecordBase> record)
|
||||||
{
|
{
|
||||||
Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record);
|
assert(record != nullptr);
|
||||||
mContainer.push_back(newRecord);
|
// convert base pointer to record type pointer
|
||||||
|
std::unique_ptr<Record<RecordT>> typedRecord(&dynamic_cast<Record<RecordT>&>(*record));
|
||||||
|
record.release();
|
||||||
|
mContainer.push_back(std::move(typedRecord));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
@ -106,33 +112,33 @@ namespace CSMWorld
|
|||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
const RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) const
|
const RecordBase& RefIdDataContainer<RecordT>::getRecord (int index) const
|
||||||
{
|
{
|
||||||
return mContainer.at (index);
|
return *mContainer.at (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
RecordBase& RefIdDataContainer<RecordT>::getRecord (int index)
|
RecordBase& RefIdDataContainer<RecordT>::getRecord (int index)
|
||||||
{
|
{
|
||||||
return mContainer.at (index);
|
return *mContainer.at (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
unsigned int RefIdDataContainer<RecordT>::getRecordFlags (int index) const
|
unsigned int RefIdDataContainer<RecordT>::getRecordFlags (int index) const
|
||||||
{
|
{
|
||||||
return mContainer.at (index).get().mRecordFlags;
|
return mContainer.at (index)->get().mRecordFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base)
|
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base)
|
||||||
{
|
{
|
||||||
Record<RecordT> record;
|
std::unique_ptr<Record<RecordT> > record(new Record<RecordT>);
|
||||||
|
|
||||||
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
record->mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
|
|
||||||
record.mBase.mId = id;
|
record->mBase.mId = id;
|
||||||
record.mModified.mId = id;
|
record->mModified.mId = id;
|
||||||
(base ? record.mBase : record.mModified).blank();
|
(base ? record->mBase : record->mModified).blank();
|
||||||
|
|
||||||
mContainer.push_back (record);
|
mContainer.push_back (std::move(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
@ -147,7 +153,7 @@ namespace CSMWorld
|
|||||||
int numRecords = static_cast<int>(mContainer.size());
|
int numRecords = static_cast<int>(mContainer.size());
|
||||||
for (; index < numRecords; ++index)
|
for (; index < numRecords; ++index)
|
||||||
{
|
{
|
||||||
if (Misc::StringUtils::ciEqual(mContainer[index].get().mId, record.mId))
|
if (Misc::StringUtils::ciEqual(mContainer[index]->get().mId, record.mId))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -165,7 +171,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
// Flag the record as Deleted even for a base content file.
|
// Flag the record as Deleted even for a base content file.
|
||||||
// RefIdData is responsible for its erasure.
|
// RefIdData is responsible for its erasure.
|
||||||
mContainer[index].mState = RecordBase::State_Deleted;
|
mContainer[index]->mState = RecordBase::State_Deleted;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -174,22 +180,22 @@ namespace CSMWorld
|
|||||||
appendRecord(record.mId, base);
|
appendRecord(record.mId, base);
|
||||||
if (base)
|
if (base)
|
||||||
{
|
{
|
||||||
mContainer.back().mBase = record;
|
mContainer.back()->mBase = record;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mContainer.back().mModified = record;
|
mContainer.back()->mModified = record;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!base)
|
else if (!base)
|
||||||
{
|
{
|
||||||
mContainer[index].setModified(record);
|
mContainer[index]->setModified(record);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Overwrite
|
// Overwrite
|
||||||
mContainer[index].setModified(record);
|
mContainer[index]->setModified(record);
|
||||||
mContainer[index].merge();
|
mContainer[index]->merge();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,13 +214,13 @@ namespace CSMWorld
|
|||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
std::string RefIdDataContainer<RecordT>::getId (int index) const
|
std::string RefIdDataContainer<RecordT>::getId (int index) const
|
||||||
{
|
{
|
||||||
return mContainer.at (index).get().mId;
|
return mContainer.at (index)->get().mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
void RefIdDataContainer<RecordT>::save (int index, ESM::ESMWriter& writer) const
|
void RefIdDataContainer<RecordT>::save (int index, ESM::ESMWriter& writer) const
|
||||||
{
|
{
|
||||||
Record<RecordT> record = mContainer.at(index);
|
const Record<RecordT>& record = *mContainer.at(index);
|
||||||
|
|
||||||
if (record.isModified() || record.mState == RecordBase::State_Deleted)
|
if (record.isModified() || record.mState == RecordBase::State_Deleted)
|
||||||
{
|
{
|
||||||
@ -272,11 +278,11 @@ namespace CSMWorld
|
|||||||
|
|
||||||
int localToGlobalIndex (const LocalIndex& index) const;
|
int localToGlobalIndex (const LocalIndex& index) const;
|
||||||
|
|
||||||
LocalIndex searchId (const std::string& id) const;
|
LocalIndex searchId(std::string_view id) const;
|
||||||
|
|
||||||
void erase (int index, int count);
|
void erase (int index, int count);
|
||||||
|
|
||||||
void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type,
|
void insertRecord (std::unique_ptr<RecordBase> record, CSMWorld::UniversalId::Type type,
|
||||||
const std::string& id);
|
const std::string& id);
|
||||||
|
|
||||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
@ -22,10 +23,8 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const *
|
|||||||
|
|
||||||
size_t baseSize = mBaseDirectory.size();
|
size_t baseSize = mBaseDirectory.size();
|
||||||
|
|
||||||
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
|
for (const auto& filepath : vfs->getRecursiveDirectoryIterator(""))
|
||||||
for (std::map<std::string, VFS::File*>::const_iterator it = index.begin(); it != index.end(); ++it)
|
|
||||||
{
|
{
|
||||||
std::string filepath = it->first;
|
|
||||||
if (filepath.size()<baseSize+1 ||
|
if (filepath.size()<baseSize+1 ||
|
||||||
filepath.substr (0, baseSize)!=mBaseDirectory ||
|
filepath.substr (0, baseSize)!=mBaseDirectory ||
|
||||||
(filepath[baseSize]!='/' && filepath[baseSize]!='\\'))
|
(filepath[baseSize]!='/' && filepath[baseSize]!='\\'))
|
||||||
@ -83,7 +82,7 @@ int CSMWorld::Resources::getIndex (const std::string& id) const
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMWorld::Resources::searchId (const std::string& id) const
|
int CSMWorld::Resources::searchId(std::string_view id) const
|
||||||
{
|
{
|
||||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "universalid.hpp"
|
#include "universalid.hpp"
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ namespace CSMWorld
|
|||||||
|
|
||||||
int getIndex (const std::string& id) const;
|
int getIndex (const std::string& id) const;
|
||||||
|
|
||||||
int searchId (const std::string& id) const;
|
int searchId(std::string_view id) const;
|
||||||
|
|
||||||
UniversalId::Type getType() const;
|
UniversalId::Type getType() const;
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
||||||
: mDocument (document), mAborted (false), mMessages (nullptr), mTotalRecords (0)
|
: mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0)
|
||||||
{
|
{
|
||||||
setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str()));
|
setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str()));
|
||||||
|
|
||||||
@ -25,26 +25,25 @@ CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
|||||||
|
|
||||||
mLayout = new QVBoxLayout (this);
|
mLayout = new QVBoxLayout (this);
|
||||||
|
|
||||||
// file progress
|
// total progress
|
||||||
mFile = new QLabel (this);
|
mTotalRecordsLabel = new QLabel (this);
|
||||||
|
|
||||||
mLayout->addWidget (mFile);
|
mLayout->addWidget (mTotalRecordsLabel);
|
||||||
|
|
||||||
mFileProgress = new QProgressBar (this);
|
mTotalProgress = new QProgressBar (this);
|
||||||
|
|
||||||
mLayout->addWidget (mFileProgress);
|
mLayout->addWidget (mTotalProgress);
|
||||||
|
|
||||||
int size = static_cast<int> (document->getContentFiles().size())+1;
|
mTotalProgress->setMinimum (0);
|
||||||
if (document->isNew())
|
mTotalProgress->setMaximum (document->getData().getTotalRecords(document->getContentFiles()));
|
||||||
--size;
|
mTotalProgress->setTextVisible (true);
|
||||||
|
mTotalProgress->setValue (0);
|
||||||
|
mTotalRecords = 0;
|
||||||
|
|
||||||
mFileProgress->setMinimum (0);
|
mFilesLoaded = 0;
|
||||||
mFileProgress->setMaximum (size);
|
|
||||||
mFileProgress->setTextVisible (true);
|
|
||||||
mFileProgress->setValue (0);
|
|
||||||
|
|
||||||
// record progress
|
// record progress
|
||||||
mLayout->addWidget (mRecords = new QLabel ("Records", this));
|
mLayout->addWidget (mRecordsLabel = new QLabel ("Records", this));
|
||||||
|
|
||||||
mRecordProgress = new QProgressBar (this);
|
mRecordProgress = new QProgressBar (this);
|
||||||
|
|
||||||
@ -74,29 +73,32 @@ CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
|||||||
connect (mButtons, SIGNAL (rejected()), this, SLOT (cancel()));
|
connect (mButtons, SIGNAL (rejected()), this, SLOT (cancel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::LoadingDocument::nextStage (const std::string& name, int totalRecords)
|
void CSVDoc::LoadingDocument::nextStage (const std::string& name, int fileRecords)
|
||||||
{
|
{
|
||||||
mFile->setText (QString::fromUtf8 (("Loading: " + name).c_str()));
|
++mFilesLoaded;
|
||||||
|
size_t numFiles = mDocument->getContentFiles().size();
|
||||||
|
|
||||||
mFileProgress->setValue (mFileProgress->value()+1);
|
mTotalRecordsLabel->setText (QString::fromUtf8 (("Loading: "+name
|
||||||
|
+" ("+std::to_string(mFilesLoaded)+" of "+std::to_string((numFiles))+")").c_str()));
|
||||||
|
|
||||||
|
mTotalRecords = mTotalProgress->value();
|
||||||
|
|
||||||
mRecordProgress->setValue (0);
|
mRecordProgress->setValue (0);
|
||||||
mRecordProgress->setMaximum (totalRecords>0 ? totalRecords : 1);
|
mRecordProgress->setMaximum (fileRecords>0 ? fileRecords : 1);
|
||||||
|
|
||||||
mTotalRecords = totalRecords;
|
mRecords = fileRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::LoadingDocument::nextRecord (int records)
|
void CSVDoc::LoadingDocument::nextRecord (int records)
|
||||||
{
|
{
|
||||||
if (records<=mTotalRecords)
|
if (records <= mRecords)
|
||||||
{
|
{
|
||||||
mRecordProgress->setValue (records);
|
mTotalProgress->setValue (mTotalRecords+records);
|
||||||
|
|
||||||
std::ostringstream stream;
|
mRecordProgress->setValue(records);
|
||||||
|
|
||||||
stream << "Records: " << records << " of " << mTotalRecords;
|
mRecordsLabel->setText(QString::fromStdString(
|
||||||
|
"Records: "+std::to_string(records)+" of "+std::to_string(mRecords)));
|
||||||
mRecords->setText (QString::fromUtf8 (stream.str().c_str()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +178,12 @@ void CSVDoc::Loader::loadingStopped (CSMDoc::Document *document, bool completed,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::Loader::nextStage (CSMDoc::Document *document, const std::string& name,
|
void CSVDoc::Loader::nextStage (CSMDoc::Document *document, const std::string& name,
|
||||||
int totalRecords)
|
int fileRecords)
|
||||||
{
|
{
|
||||||
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
|
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
|
||||||
|
|
||||||
if (iter!=mDocuments.end())
|
if (iter!=mDocuments.end())
|
||||||
iter->second->nextStage (name, totalRecords);
|
iter->second->nextStage (name, fileRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::Loader::nextRecord (CSMDoc::Document *document, int records)
|
void CSVDoc::Loader::nextRecord (CSMDoc::Document *document, int records)
|
||||||
|
@ -25,16 +25,18 @@ namespace CSVDoc
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
CSMDoc::Document *mDocument;
|
CSMDoc::Document *mDocument;
|
||||||
QLabel *mFile;
|
QLabel *mTotalRecordsLabel;
|
||||||
QLabel *mRecords;
|
QLabel *mRecordsLabel;
|
||||||
QProgressBar *mFileProgress;
|
QProgressBar *mTotalProgress;
|
||||||
QProgressBar *mRecordProgress;
|
QProgressBar *mRecordProgress;
|
||||||
bool mAborted;
|
bool mAborted;
|
||||||
QDialogButtonBox *mButtons;
|
QDialogButtonBox *mButtons;
|
||||||
QLabel *mError;
|
QLabel *mError;
|
||||||
QListWidget *mMessages;
|
QListWidget *mMessages;
|
||||||
QVBoxLayout *mLayout;
|
QVBoxLayout *mLayout;
|
||||||
|
int mRecords;
|
||||||
int mTotalRecords;
|
int mTotalRecords;
|
||||||
|
int mFilesLoaded;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ void CSVDoc::View::setupFileMenu()
|
|||||||
QAction* save = createMenuEntry("Save", ":./menu-save.png", file, "document-file-save");
|
QAction* save = createMenuEntry("Save", ":./menu-save.png", file, "document-file-save");
|
||||||
connect (save, SIGNAL (triggered()), this, SLOT (save()));
|
connect (save, SIGNAL (triggered()), this, SLOT (save()));
|
||||||
mSave = save;
|
mSave = save;
|
||||||
|
|
||||||
|
file->addSeparator();
|
||||||
|
|
||||||
QAction* verify = createMenuEntry("Verify", ":./menu-verify.png", file, "document-file-verify");
|
QAction* verify = createMenuEntry("Verify", ":./menu-verify.png", file, "document-file-verify");
|
||||||
connect (verify, SIGNAL (triggered()), this, SLOT (verify()));
|
connect (verify, SIGNAL (triggered()), this, SLOT (verify()));
|
||||||
@ -80,6 +82,8 @@ void CSVDoc::View::setupFileMenu()
|
|||||||
QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata");
|
QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata");
|
||||||
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
|
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
|
||||||
|
|
||||||
|
file->addSeparator();
|
||||||
|
|
||||||
QAction* close = createMenuEntry("Close", ":./menu-close.png", file, "document-file-close");
|
QAction* close = createMenuEntry("Close", ":./menu-close.png", file, "document-file-close");
|
||||||
connect (close, SIGNAL (triggered()), this, SLOT (close()));
|
connect (close, SIGNAL (triggered()), this, SLOT (close()));
|
||||||
|
|
||||||
@ -156,17 +160,16 @@ void CSVDoc::View::setupWorldMenu()
|
|||||||
{
|
{
|
||||||
QMenu *world = menuBar()->addMenu (tr ("World"));
|
QMenu *world = menuBar()->addMenu (tr ("World"));
|
||||||
|
|
||||||
QAction* regions = createMenuEntry(CSMWorld::UniversalId::Type_Regions, world, "document-world-regions");
|
|
||||||
connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView()));
|
|
||||||
|
|
||||||
QAction* cells = createMenuEntry(CSMWorld::UniversalId::Type_Cells, world, "document-world-cells");
|
|
||||||
connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView()));
|
|
||||||
|
|
||||||
QAction* referenceables = createMenuEntry(CSMWorld::UniversalId::Type_Referenceables, world, "document-world-referencables");
|
QAction* referenceables = createMenuEntry(CSMWorld::UniversalId::Type_Referenceables, world, "document-world-referencables");
|
||||||
connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView()));
|
connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView()));
|
||||||
|
|
||||||
QAction* references = createMenuEntry(CSMWorld::UniversalId::Type_References, world, "document-world-references");
|
QAction* references = createMenuEntry(CSMWorld::UniversalId::Type_References, world, "document-world-references");
|
||||||
connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView()));
|
connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView()));
|
||||||
|
|
||||||
|
world->addSeparator();
|
||||||
|
|
||||||
|
QAction* cells = createMenuEntry(CSMWorld::UniversalId::Type_Cells, world, "document-world-cells");
|
||||||
|
connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView()));
|
||||||
|
|
||||||
QAction *lands = createMenuEntry(CSMWorld::UniversalId::Type_Lands, world, "document-world-lands");
|
QAction *lands = createMenuEntry(CSMWorld::UniversalId::Type_Lands, world, "document-world-lands");
|
||||||
connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView()));
|
connect (lands, SIGNAL (triggered()), this, SLOT (addLandsSubView()));
|
||||||
@ -177,7 +180,10 @@ void CSVDoc::View::setupWorldMenu()
|
|||||||
QAction *grid = createMenuEntry(CSMWorld::UniversalId::Type_Pathgrids, world, "document-world-pathgrid");
|
QAction *grid = createMenuEntry(CSMWorld::UniversalId::Type_Pathgrids, world, "document-world-pathgrid");
|
||||||
connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView()));
|
connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView()));
|
||||||
|
|
||||||
world->addSeparator(); // items that don't represent single record lists follow here
|
world->addSeparator();
|
||||||
|
|
||||||
|
QAction* regions = createMenuEntry(CSMWorld::UniversalId::Type_Regions, world, "document-world-regions");
|
||||||
|
connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView()));
|
||||||
|
|
||||||
QAction *regionMap = createMenuEntry(CSMWorld::UniversalId::Type_RegionMap, world, "document-world-regionmap");
|
QAction *regionMap = createMenuEntry(CSMWorld::UniversalId::Type_RegionMap, world, "document-world-regionmap");
|
||||||
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
||||||
@ -187,14 +193,19 @@ void CSVDoc::View::setupMechanicsMenu()
|
|||||||
{
|
{
|
||||||
QMenu *mechanics = menuBar()->addMenu (tr ("Mechanics"));
|
QMenu *mechanics = menuBar()->addMenu (tr ("Mechanics"));
|
||||||
|
|
||||||
|
QAction* scripts = createMenuEntry(CSMWorld::UniversalId::Type_Scripts, mechanics, "document-mechanics-scripts");
|
||||||
|
connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView()));
|
||||||
|
|
||||||
|
QAction* startScripts = createMenuEntry(CSMWorld::UniversalId::Type_StartScripts, mechanics, "document-mechanics-startscripts");
|
||||||
|
connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView()));
|
||||||
|
|
||||||
QAction* globals = createMenuEntry(CSMWorld::UniversalId::Type_Globals, mechanics, "document-mechanics-globals");
|
QAction* globals = createMenuEntry(CSMWorld::UniversalId::Type_Globals, mechanics, "document-mechanics-globals");
|
||||||
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
|
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
|
||||||
|
|
||||||
QAction* gmsts = createMenuEntry(CSMWorld::UniversalId::Type_Gmsts, mechanics, "document-mechanics-gamesettings");
|
QAction* gmsts = createMenuEntry(CSMWorld::UniversalId::Type_Gmsts, mechanics, "document-mechanics-gamesettings");
|
||||||
connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView()));
|
connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView()));
|
||||||
|
|
||||||
QAction* scripts = createMenuEntry(CSMWorld::UniversalId::Type_Scripts, mechanics, "document-mechanics-scripts");
|
mechanics->addSeparator();
|
||||||
connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView()));
|
|
||||||
|
|
||||||
QAction* spells = createMenuEntry(CSMWorld::UniversalId::Type_Spells, mechanics, "document-mechanics-spells");
|
QAction* spells = createMenuEntry(CSMWorld::UniversalId::Type_Spells, mechanics, "document-mechanics-spells");
|
||||||
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
|
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
|
||||||
@ -204,9 +215,6 @@ void CSVDoc::View::setupMechanicsMenu()
|
|||||||
|
|
||||||
QAction* magicEffects = createMenuEntry(CSMWorld::UniversalId::Type_MagicEffects, mechanics, "document-mechanics-magiceffects");
|
QAction* magicEffects = createMenuEntry(CSMWorld::UniversalId::Type_MagicEffects, mechanics, "document-mechanics-magiceffects");
|
||||||
connect (magicEffects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView()));
|
connect (magicEffects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView()));
|
||||||
|
|
||||||
QAction* startScripts = createMenuEntry(CSMWorld::UniversalId::Type_StartScripts, mechanics, "document-mechanics-startscripts");
|
|
||||||
connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::View::setupCharacterMenu()
|
void CSVDoc::View::setupCharacterMenu()
|
||||||
@ -227,21 +235,25 @@ void CSVDoc::View::setupCharacterMenu()
|
|||||||
|
|
||||||
QAction* birthsigns = createMenuEntry(CSMWorld::UniversalId::Type_Birthsigns, characters, "document-character-birthsigns");
|
QAction* birthsigns = createMenuEntry(CSMWorld::UniversalId::Type_Birthsigns, characters, "document-character-birthsigns");
|
||||||
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
|
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
|
||||||
|
|
||||||
|
QAction* bodyParts = createMenuEntry(CSMWorld::UniversalId::Type_BodyParts, characters, "document-character-bodyparts");
|
||||||
|
connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView()));
|
||||||
|
|
||||||
|
characters->addSeparator();
|
||||||
|
|
||||||
QAction* topics = createMenuEntry(CSMWorld::UniversalId::Type_Topics, characters, "document-character-topics");
|
QAction* topics = createMenuEntry(CSMWorld::UniversalId::Type_Topics, characters, "document-character-topics");
|
||||||
connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView()));
|
connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView()));
|
||||||
|
|
||||||
|
QAction* topicInfos = createMenuEntry(CSMWorld::UniversalId::Type_TopicInfos, characters, "document-character-topicinfos");
|
||||||
|
connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView()));
|
||||||
|
|
||||||
|
characters->addSeparator();
|
||||||
|
|
||||||
QAction* journals = createMenuEntry(CSMWorld::UniversalId::Type_Journals, characters, "document-character-journals");
|
QAction* journals = createMenuEntry(CSMWorld::UniversalId::Type_Journals, characters, "document-character-journals");
|
||||||
connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView()));
|
connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView()));
|
||||||
|
|
||||||
QAction* topicInfos = createMenuEntry(CSMWorld::UniversalId::Type_TopicInfos, characters, "document-character-topicinfos");
|
|
||||||
connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView()));
|
|
||||||
|
|
||||||
QAction* journalInfos = createMenuEntry(CSMWorld::UniversalId::Type_JournalInfos, characters, "document-character-journalinfos");
|
QAction* journalInfos = createMenuEntry(CSMWorld::UniversalId::Type_JournalInfos, characters, "document-character-journalinfos");
|
||||||
connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView()));
|
connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView()));
|
||||||
|
|
||||||
QAction* bodyParts = createMenuEntry(CSMWorld::UniversalId::Type_BodyParts, characters, "document-character-bodyparts");
|
|
||||||
connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::View::setupAssetsMenu()
|
void CSVDoc::View::setupAssetsMenu()
|
||||||
|
@ -96,7 +96,7 @@ namespace CSVRender
|
|||||||
for (int i = 0; i < ESM::PRT_Count; ++i)
|
for (int i = 0; i < ESM::PRT_Count; ++i)
|
||||||
{
|
{
|
||||||
auto type = (ESM::PartReferenceType) i;
|
auto type = (ESM::PartReferenceType) i;
|
||||||
std::string partId = mActorData->getPart(type);
|
const std::string_view partId = mActorData->getPart(type);
|
||||||
attachBodyPart(type, getBodyPartMesh(partId));
|
attachBodyPart(type, getBodyPartMesh(partId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ namespace CSVRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Actor::getBodyPartMesh(const std::string& bodyPartId)
|
std::string Actor::getBodyPartMesh(std::string_view bodyPartId)
|
||||||
{
|
{
|
||||||
const auto& bodyParts = mData.getBodyParts();
|
const auto& bodyParts = mData.getBodyParts();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define OPENCS_VIEW_RENDER_ACTOR_H
|
#define OPENCS_VIEW_RENDER_ACTOR_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ namespace CSVRender
|
|||||||
void loadBodyParts();
|
void loadBodyParts();
|
||||||
void attachBodyPart(ESM::PartReferenceType, const std::string& mesh);
|
void attachBodyPart(ESM::PartReferenceType, const std::string& mesh);
|
||||||
|
|
||||||
std::string getBodyPartMesh(const std::string& bodyPartId);
|
std::string getBodyPartMesh(std::string_view bodyPartId);
|
||||||
|
|
||||||
static const std::string MeshPrefix;
|
static const std::string MeshPrefix;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ CSVRender::BrushDraw::BrushDraw(osg::ref_ptr<osg::Group> parentNode, bool textur
|
|||||||
mBrushDrawNode = new osg::Group();
|
mBrushDrawNode = new osg::Group();
|
||||||
mGeometry = new osg::Geometry();
|
mGeometry = new osg::Geometry();
|
||||||
mBrushDrawNode->addChild(mGeometry);
|
mBrushDrawNode->addChild(mGeometry);
|
||||||
|
mBrushDrawNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
mBrushDrawNode->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
|
||||||
mParentNode->addChild(mBrushDrawNode);
|
mParentNode->addChild(mBrushDrawNode);
|
||||||
if (mTextureMode)
|
if (mTextureMode)
|
||||||
mLandSizeFactor = static_cast<float>(ESM::Land::REAL_SIZE) / static_cast<float>(ESM::Land::LAND_TEXTURE_SIZE);
|
mLandSizeFactor = static_cast<float>(ESM::Land::REAL_SIZE) / static_cast<float>(ESM::Land::LAND_TEXTURE_SIZE);
|
||||||
@ -122,7 +124,14 @@ void CSVRender::BrushDraw::buildSquareGeometry(const float& radius, const osg::V
|
|||||||
const float brushOutlineHeight (1.0f);
|
const float brushOutlineHeight (1.0f);
|
||||||
float diameter = radius * 2;
|
float diameter = radius * 2;
|
||||||
int resolution = static_cast<int>(2.f * diameter / mLandSizeFactor); //half a vertex resolution
|
int resolution = static_cast<int>(2.f * diameter / mLandSizeFactor); //half a vertex resolution
|
||||||
float resAdjustedLandSizeFactor = mLandSizeFactor / 2;
|
float resAdjustedLandSizeFactor = mLandSizeFactor / 2; //128
|
||||||
|
|
||||||
|
if (resolution > 128) // limit accuracy for performance
|
||||||
|
{
|
||||||
|
resolution = 128;
|
||||||
|
resAdjustedLandSizeFactor = diameter / resolution;
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
||||||
|
|
||||||
for (int i = 0; i < resolution; i++)
|
for (int i = 0; i < resolution; i++)
|
||||||
@ -215,7 +224,8 @@ void CSVRender::BrushDraw::buildCircleGeometry(const float& radius, const osg::V
|
|||||||
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry());
|
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry());
|
||||||
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
|
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
|
||||||
osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array());
|
osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array());
|
||||||
const int amountOfPoints = (osg::PI * 2.0f) * radius / 20;
|
|
||||||
|
const int amountOfPoints = 128;
|
||||||
const float step ((osg::PI * 2.0f) / static_cast<float>(amountOfPoints));
|
const float step ((osg::PI * 2.0f) / static_cast<float>(amountOfPoints));
|
||||||
const float brushOutlineHeight (1.0f);
|
const float brushOutlineHeight (1.0f);
|
||||||
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
osg::Vec4f lineColor(1.0f, 1.0f, 1.0f, 0.6f);
|
||||||
|
@ -60,7 +60,7 @@ void CSVRender::CellArrow::adjustTransform()
|
|||||||
{
|
{
|
||||||
// position
|
// position
|
||||||
const int cellSize = Constants::CellSizeInUnits;
|
const int cellSize = Constants::CellSizeInUnits;
|
||||||
const int offset = cellSize / 2 + 800;
|
const int offset = cellSize / 2 + 600;
|
||||||
|
|
||||||
int x = mCoordinates.getX()*cellSize + cellSize/2;
|
int x = mCoordinates.getX()*cellSize + cellSize/2;
|
||||||
int y = mCoordinates.getY()*cellSize + cellSize/2;
|
int y = mCoordinates.getY()*cellSize + cellSize/2;
|
||||||
@ -92,9 +92,9 @@ void CSVRender::CellArrow::buildShape()
|
|||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
|
||||||
|
|
||||||
const int arrowWidth = 4000;
|
const int arrowWidth = 2700;
|
||||||
const int arrowLength = 1500;
|
const int arrowLength = 1350;
|
||||||
const int arrowHeight = 500;
|
const int arrowHeight = 300;
|
||||||
|
|
||||||
osg::Vec3Array *vertices = new osg::Vec3Array;
|
osg::Vec3Array *vertices = new osg::Vec3Array;
|
||||||
for (int i2=0; i2<2; ++i2)
|
for (int i2=0; i2<2; ++i2)
|
||||||
|
@ -1,19 +1,44 @@
|
|||||||
#include "commands.hpp"
|
#include "commands.hpp"
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/esm/loadland.hpp>
|
#include <components/esm/loadland.hpp>
|
||||||
|
|
||||||
|
#include "editmode.hpp"
|
||||||
#include "terrainselection.hpp"
|
#include "terrainselection.hpp"
|
||||||
|
#include "terrainshapemode.hpp"
|
||||||
|
#include "terraintexturemode.hpp"
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent)
|
CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent)
|
||||||
: mTerrainSelection(terrainSelection)
|
: mWorldspaceWidget(worldspaceWidget)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void CSVRender::DrawTerrainSelectionCommand::redo()
|
void CSVRender::DrawTerrainSelectionCommand::redo()
|
||||||
{
|
{
|
||||||
mTerrainSelection.update();
|
tryUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::DrawTerrainSelectionCommand::undo()
|
void CSVRender::DrawTerrainSelectionCommand::undo()
|
||||||
{
|
{
|
||||||
mTerrainSelection.update();
|
tryUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVRender::DrawTerrainSelectionCommand::tryUpdate()
|
||||||
|
{
|
||||||
|
if (!mWorldspaceWidget)
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "Can't update terrain selection, no WorldspaceWidget found!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto terrainMode = dynamic_cast<CSVRender::TerrainShapeMode*>(mWorldspaceWidget->getEditMode());
|
||||||
|
if (!terrainMode)
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "Can't update terrain selection in current EditMode";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
terrainMode->getTerrainSelection()->update();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#ifndef CSV_RENDER_COMMANDS_HPP
|
#ifndef CSV_RENDER_COMMANDS_HPP
|
||||||
#define CSV_RENDER_COMMANDS_HPP
|
#define CSV_RENDER_COMMANDS_HPP
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
#include <QUndoCommand>
|
#include <QUndoCommand>
|
||||||
|
|
||||||
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
namespace CSVRender
|
namespace CSVRender
|
||||||
{
|
{
|
||||||
class TerrainSelection;
|
class TerrainSelection;
|
||||||
@ -21,14 +25,17 @@ namespace CSVRender
|
|||||||
*/
|
*/
|
||||||
class DrawTerrainSelectionCommand : public QUndoCommand
|
class DrawTerrainSelectionCommand : public QUndoCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TerrainSelection& mTerrainSelection;
|
QPointer<WorldspaceWidget> mWorldspaceWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent = nullptr);
|
DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent = nullptr);
|
||||||
|
|
||||||
void redo() override;
|
void redo() override;
|
||||||
void undo() override;
|
void undo() override;
|
||||||
|
|
||||||
|
void tryUpdate();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +297,8 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mObjectsAtDragStart.clear();
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
||||||
iter!=selection.end(); ++iter)
|
iter!=selection.end(); ++iter)
|
||||||
{
|
{
|
||||||
@ -305,6 +307,12 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
|
|||||||
if (mSubModeId == "move")
|
if (mSubModeId == "move")
|
||||||
{
|
{
|
||||||
objectTag->mObject->setEdited (Object::Override_Position);
|
objectTag->mObject->setEdited (Object::Override_Position);
|
||||||
|
float x = objectTag->mObject->getPosition().pos[0];
|
||||||
|
float y = objectTag->mObject->getPosition().pos[1];
|
||||||
|
float z = objectTag->mObject->getPosition().pos[2];
|
||||||
|
osg::Vec3f thisPoint(x, y, z);
|
||||||
|
mDragStart = getMousePlaneCoords(pos, getProjectionSpaceCoords(thisPoint));
|
||||||
|
mObjectsAtDragStart.emplace_back(thisPoint);
|
||||||
mDragMode = DragMode_Move;
|
mDragMode = DragMode_Move;
|
||||||
}
|
}
|
||||||
else if (mSubModeId == "rotate")
|
else if (mSubModeId == "rotate")
|
||||||
@ -392,29 +400,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||||||
|
|
||||||
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference);
|
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference);
|
||||||
|
|
||||||
if (mDragMode == DragMode_Move)
|
if (mDragMode == DragMode_Move) {}
|
||||||
{
|
|
||||||
osg::Vec3f eye, centre, up;
|
|
||||||
getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up);
|
|
||||||
|
|
||||||
if (diffY)
|
|
||||||
{
|
|
||||||
offset += up * diffY * speedFactor;
|
|
||||||
}
|
|
||||||
if (diffX)
|
|
||||||
{
|
|
||||||
offset += ((centre-eye) ^ up) * diffX * speedFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mDragAxis!=-1)
|
|
||||||
{
|
|
||||||
for (int i=0; i<3; ++i)
|
|
||||||
{
|
|
||||||
if (i!=mDragAxis)
|
|
||||||
offset[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mDragMode == DragMode_Rotate)
|
else if (mDragMode == DragMode_Rotate)
|
||||||
{
|
{
|
||||||
osg::Vec3f eye, centre, up;
|
osg::Vec3f eye, centre, up;
|
||||||
@ -514,17 +500,32 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
// Apply
|
// Apply
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin()); iter!=selection.end(); ++iter)
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin()); iter!=selection.end(); ++iter, i++)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||||
{
|
{
|
||||||
if (mDragMode == DragMode_Move)
|
if (mDragMode == DragMode_Move)
|
||||||
{
|
{
|
||||||
ESM::Position position = objectTag->mObject->getPosition();
|
ESM::Position position = objectTag->mObject->getPosition();
|
||||||
for (int i=0; i<3; ++i)
|
osg::Vec3f mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart));
|
||||||
|
float addToX = mousePos.x() - mDragStart.x();
|
||||||
|
float addToY = mousePos.y() - mDragStart.y();
|
||||||
|
float addToZ = mousePos.z() - mDragStart.z();
|
||||||
|
position.pos[0] = mObjectsAtDragStart[i].x() + addToX;
|
||||||
|
position.pos[1] = mObjectsAtDragStart[i].y() + addToY;
|
||||||
|
position.pos[2] = mObjectsAtDragStart[i].z() + addToZ;
|
||||||
|
|
||||||
|
// XYZ-locking
|
||||||
|
if (mDragAxis != -1)
|
||||||
{
|
{
|
||||||
position.pos[i] += offset[i];
|
for (int j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
if (j != mDragAxis)
|
||||||
|
position.pos[j] = mObjectsAtDragStart[i][j];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objectTag->mObject->setPosition(position.pos);
|
objectTag->mObject->setPosition(position.pos);
|
||||||
@ -608,6 +609,7 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mObjectsAtDragStart.clear();
|
||||||
mDragMode = DragMode_None;
|
mDragMode = DragMode_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,8 +636,10 @@ void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor)
|
|||||||
std::vector<osg::ref_ptr<TagBase> > selection =
|
std::vector<osg::ref_ptr<TagBase> > selection =
|
||||||
getWorldspaceWidget().getEdited (Mask_Reference);
|
getWorldspaceWidget().getEdited (Mask_Reference);
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
for (std::vector<osg::ref_ptr<TagBase> >::iterator iter (selection.begin());
|
||||||
iter!=selection.end(); ++iter)
|
iter!=selection.end(); ++iter, j++)
|
||||||
{
|
{
|
||||||
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (iter->get()))
|
||||||
{
|
{
|
||||||
@ -643,6 +647,9 @@ void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor)
|
|||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
position.pos[i] += offset[i];
|
position.pos[i] += offset[i];
|
||||||
objectTag->mObject->setPosition (position.pos);
|
objectTag->mObject->setPosition (position.pos);
|
||||||
|
osg::Vec3f thisPoint(position.pos[0], position.pos[1], position.pos[2]);
|
||||||
|
mDragStart = getMousePlaneCoords(getWorldspaceWidget().mapFromGlobal(QCursor::pos()), getProjectionSpaceCoords(thisPoint));
|
||||||
|
mObjectsAtDragStart[j] = thisPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ namespace CSVRender
|
|||||||
bool mLocked;
|
bool mLocked;
|
||||||
float mUnitScaleDist;
|
float mUnitScaleDist;
|
||||||
osg::ref_ptr<osg::Group> mParentNode;
|
osg::ref_ptr<osg::Group> mParentNode;
|
||||||
|
osg::Vec3f mDragStart;
|
||||||
|
std::vector<osg::Vec3f> mObjectsAtDragStart;
|
||||||
|
|
||||||
int getSubModeFromId (const std::string& id) const;
|
int getSubModeFromId (const std::string& id) const;
|
||||||
|
|
||||||
|
@ -682,18 +682,20 @@ void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
|
|||||||
|
|
||||||
int cellColumn = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
|
int cellColumn = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
|
||||||
CSMWorld::Columns::ColumnId_Cell));
|
CSMWorld::Columns::ColumnId_Cell));
|
||||||
int refNumColumn = collection.findColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (
|
int origCellColumn = collection.findColumnIndex(static_cast<CSMWorld::Columns::ColumnId> (
|
||||||
CSMWorld::Columns::ColumnId_RefNum));
|
CSMWorld::Columns::ColumnId_OriginalCell));
|
||||||
|
|
||||||
if (cellIndex != originalIndex)
|
if (cellIndex != originalIndex)
|
||||||
{
|
{
|
||||||
/// \todo figure out worldspace (not important until multiple worldspaces are supported)
|
/// \todo figure out worldspace (not important until multiple worldspaces are supported)
|
||||||
|
std::string origCellId = CSMWorld::CellCoordinates(originalIndex).getId("");
|
||||||
std::string cellId = CSMWorld::CellCoordinates (cellIndex).getId ("");
|
std::string cellId = CSMWorld::CellCoordinates (cellIndex).getId ("");
|
||||||
|
|
||||||
commands.push (new CSMWorld::ModifyCommand (*model,
|
commands.push (new CSMWorld::ModifyCommand (*model,
|
||||||
model->index (recordIndex, cellColumn), QString::fromUtf8 (cellId.c_str())));
|
model->index (recordIndex, origCellColumn), QString::fromUtf8 (origCellId.c_str())));
|
||||||
commands.push (new CSMWorld::ModifyCommand( *model,
|
commands.push(new CSMWorld::ModifyCommand(*model,
|
||||||
model->index (recordIndex, refNumColumn), 0));
|
model->index(recordIndex, cellColumn), QString::fromUtf8(cellId.c_str())));
|
||||||
|
// NOTE: refnum is not modified for moving a reference to another cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
|
|||||||
undoStack.beginMacro ("Edit shape and normal records");
|
undoStack.beginMacro ("Edit shape and normal records");
|
||||||
|
|
||||||
// One command at the beginning of the macro for redrawing the terrain-selection grid when undoing the changes.
|
// One command at the beginning of the macro for redrawing the terrain-selection grid when undoing the changes.
|
||||||
undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection));
|
undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget()));
|
||||||
|
|
||||||
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
|
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
|
||||||
{
|
{
|
||||||
@ -358,7 +358,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges()
|
|||||||
pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId);
|
pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId);
|
||||||
}
|
}
|
||||||
// One command at the end of the macro for redrawing the terrain-selection grid when redoing the changes.
|
// One command at the end of the macro for redrawing the terrain-selection grid when redoing the changes.
|
||||||
undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection));
|
undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget()));
|
||||||
|
|
||||||
undoStack.endMacro();
|
undoStack.endMacro();
|
||||||
clearTransientEdits();
|
clearTransientEdits();
|
||||||
@ -1049,7 +1049,7 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob
|
|||||||
*/
|
*/
|
||||||
if (xIsAtCellBorder && yIsAtCellBorder)
|
if (xIsAtCellBorder && yIsAtCellBorder)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Handle the NW, NE, and SE corner vertices.
|
Handle the NW, NE, and SE corner vertices.
|
||||||
NW corner: (+1, -1) offset to reach current cell.
|
NW corner: (+1, -1) offset to reach current cell.
|
||||||
NE corner: (-1, -1) offset to reach current cell.
|
NE corner: (-1, -1) offset to reach current cell.
|
||||||
@ -1132,7 +1132,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
|
|||||||
selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString();
|
selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString();
|
||||||
else
|
else
|
||||||
selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString();
|
selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString();
|
||||||
|
|
||||||
if (selectAction == "Select only")
|
if (selectAction == "Select only")
|
||||||
mTerrainShapeSelection->onlySelect(selections);
|
mTerrainShapeSelection->onlySelect(selections);
|
||||||
else if (selectAction == "Add to selection")
|
else if (selectAction == "Add to selection")
|
||||||
@ -1444,6 +1444,11 @@ void CSVRender::TerrainShapeMode::mouseMoveEvent (QMouseEvent *event)
|
|||||||
mBrushDraw->hide();
|
mBrushDraw->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CSVRender::TerrainSelection> CSVRender::TerrainShapeMode::getTerrainSelection()
|
||||||
|
{
|
||||||
|
return mTerrainShapeSelection;
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainShapeMode::setBrushSize(int brushSize)
|
void CSVRender::TerrainShapeMode::setBrushSize(int brushSize)
|
||||||
{
|
{
|
||||||
mBrushSize = brushSize;
|
mBrushSize = brushSize;
|
||||||
|
@ -92,6 +92,8 @@ namespace CSVRender
|
|||||||
void dragMoveEvent (QDragMoveEvent *event) override;
|
void dragMoveEvent (QDragMoveEvent *event) override;
|
||||||
void mouseMoveEvent (QMouseEvent *event) override;
|
void mouseMoveEvent (QMouseEvent *event) override;
|
||||||
|
|
||||||
|
std::shared_ptr<TerrainSelection> getTerrainSelection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Remove duplicates and sort mAlteredCells, then limitAlteredHeights forward and reverse
|
/// Remove duplicates and sort mAlteredCells, then limitAlteredHeights forward and reverse
|
||||||
@ -176,7 +178,7 @@ namespace CSVRender
|
|||||||
int mDragMode = InteractionType_None;
|
int mDragMode = InteractionType_None;
|
||||||
osg::Group* mParentNode;
|
osg::Group* mParentNode;
|
||||||
bool mIsEditing = false;
|
bool mIsEditing = false;
|
||||||
std::unique_ptr<TerrainSelection> mTerrainShapeSelection;
|
std::shared_ptr<TerrainSelection> mTerrainShapeSelection;
|
||||||
int mTotalDiffY = 0;
|
int mTotalDiffY = 0;
|
||||||
std::vector<CSMWorld::CellCoordinates> mAlteredCells;
|
std::vector<CSMWorld::CellCoordinates> mAlteredCells;
|
||||||
osg::Vec3d mEditingPos;
|
osg::Vec3d mEditingPos;
|
||||||
|
@ -712,6 +712,11 @@ void CSVRender::TerrainTextureMode::mouseMoveEvent (QMouseEvent *event)
|
|||||||
mBrushDraw->hide();
|
mBrushDraw->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CSVRender::TerrainSelection> CSVRender::TerrainTextureMode::getTerrainSelection()
|
||||||
|
{
|
||||||
|
return mTerrainTextureSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
void CSVRender::TerrainTextureMode::setBrushSize(int brushSize)
|
||||||
{
|
{
|
||||||
|
@ -85,6 +85,8 @@ namespace CSVRender
|
|||||||
|
|
||||||
void mouseMoveEvent (QMouseEvent *event) override;
|
void mouseMoveEvent (QMouseEvent *event) override;
|
||||||
|
|
||||||
|
std::shared_ptr<TerrainSelection> getTerrainSelection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
/// \brief Handle brush mechanics, maths regarding worldspace hit etc.
|
||||||
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
void editTerrainTextureGrid (const WorldspaceHitResult& hit);
|
||||||
@ -115,7 +117,7 @@ namespace CSVRender
|
|||||||
int mDragMode;
|
int mDragMode;
|
||||||
osg::Group* mParentNode;
|
osg::Group* mParentNode;
|
||||||
bool mIsEditing;
|
bool mIsEditing;
|
||||||
std::unique_ptr<TerrainSelection> mTerrainTextureSelection;
|
std::shared_ptr<TerrainSelection> mTerrainTextureSelection;
|
||||||
|
|
||||||
const int cellSize {ESM::Land::REAL_SIZE};
|
const int cellSize {ESM::Land::REAL_SIZE};
|
||||||
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE};
|
||||||
|
@ -452,6 +452,11 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo
|
|||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
|
||||||
|
{
|
||||||
|
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::abortDrag()
|
void CSVRender::WorldspaceWidget::abortDrag()
|
||||||
{
|
{
|
||||||
if (mDragging)
|
if (mDragging)
|
||||||
@ -697,11 +702,6 @@ void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitRes
|
|||||||
editMode.primaryOpenPressed (hit);
|
editMode.primaryOpenPressed (hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
|
|
||||||
{
|
|
||||||
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
|
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
|
||||||
{
|
{
|
||||||
handleInteraction(InteractionType_PrimaryOpen, activate);
|
handleInteraction(InteractionType_PrimaryOpen, activate);
|
||||||
|
@ -189,6 +189,8 @@ namespace CSVRender
|
|||||||
/// Erase all overrides and restore the visual representation to its true state.
|
/// Erase all overrides and restore the visual representation to its true state.
|
||||||
virtual void reset (unsigned int elementMask) = 0;
|
virtual void reset (unsigned int elementMask) = 0;
|
||||||
|
|
||||||
|
EditMode *getEditMode();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// Visual elements in a scene
|
/// Visual elements in a scene
|
||||||
@ -215,8 +217,6 @@ namespace CSVRender
|
|||||||
|
|
||||||
void settingChanged (const CSMPrefs::Setting *setting) override;
|
void settingChanged (const CSMPrefs::Setting *setting) override;
|
||||||
|
|
||||||
EditMode *getEditMode();
|
|
||||||
|
|
||||||
bool getSpeedMode();
|
bool getSpeedMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef CSV_TOOLS_REPORTTABLE_H
|
#ifndef CSV_TOOLS_MERGE_H
|
||||||
#define CSV_TOOLS_REPORTTABLE_H
|
#define CSV_TOOLS_MERGE_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ void CSVTools::SearchSubView::replace (bool selection)
|
|||||||
// in a single string.
|
// in a single string.
|
||||||
for (std::vector<int>::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter)
|
for (std::vector<int>::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter)
|
||||||
{
|
{
|
||||||
CSMWorld::UniversalId id = model.getUniversalId (*iter);
|
const CSMWorld::UniversalId& id = model.getUniversalId (*iter);
|
||||||
|
|
||||||
CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType());
|
CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType());
|
||||||
|
|
||||||
|
@ -179,10 +179,10 @@ void CSVWidget::TextureBrushWindow::setBrushTexture(std::string brushTexture)
|
|||||||
undoStack.endMacro();
|
undoStack.endMacro();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != -1 && !landtexturesCollection.getRecord(index).isDeleted())
|
if (index != -1 && !landtexturesCollection.getRecord(rowInNew).isDeleted())
|
||||||
{
|
{
|
||||||
mBrushTextureLabel = "Selected texture: " + newBrushTextureId + " ";
|
mBrushTextureLabel = "Selected texture: " + newBrushTextureId + " ";
|
||||||
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(index, landTextureFilename).value<QString>());
|
mSelectedBrush->setText(QString::fromStdString(mBrushTextureLabel) + landtexturesCollection.getData(rowInNew, landTextureFilename).value<QString>());
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
newBrushTextureId = "";
|
newBrushTextureId = "";
|
||||||
|
@ -84,6 +84,13 @@ void CSVWorld::CellCreator::setType (int index)
|
|||||||
mYLabel->setVisible (index==1);
|
mYLabel->setVisible (index==1);
|
||||||
mY->setVisible (index==1);
|
mY->setVisible (index==1);
|
||||||
|
|
||||||
|
// The cell name is limited to 64 characters. (ESM::Header::GMDT::mCurrentCell)
|
||||||
|
std::string text = mType->currentText().toStdString();
|
||||||
|
if (text == "Interior Cell")
|
||||||
|
GenericCreator::setEditorMaxLength (64);
|
||||||
|
else
|
||||||
|
GenericCreator::setEditorMaxLength (32767);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,6 +538,9 @@ void CSVWorld::EditWidget::remake(int row)
|
|||||||
mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred);
|
mainLayout->addLayout(tablesLayout, QSizePolicy::Preferred);
|
||||||
mainLayout->addStretch(1);
|
mainLayout->addStretch(1);
|
||||||
|
|
||||||
|
int blockedColumn = mTable->searchColumnIndex(CSMWorld::Columns::ColumnId_Blocked);
|
||||||
|
bool isBlocked = mTable->data(mTable->index(row, blockedColumn)).toInt();
|
||||||
|
|
||||||
int unlocked = 0;
|
int unlocked = 0;
|
||||||
int locked = 0;
|
int locked = 0;
|
||||||
const int columns = mTable->columnCount();
|
const int columns = mTable->columnCount();
|
||||||
@ -583,6 +586,8 @@ void CSVWorld::EditWidget::remake(int row)
|
|||||||
NestedTable* table =
|
NestedTable* table =
|
||||||
new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows);
|
new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows);
|
||||||
table->resizeColumnsToContents();
|
table->resizeColumnsToContents();
|
||||||
|
if (isBlocked)
|
||||||
|
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
|
||||||
int rows = mTable->rowCount(mTable->index(row, i));
|
int rows = mTable->rowCount(mTable->index(row, i));
|
||||||
int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0);
|
int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0);
|
||||||
@ -617,7 +622,9 @@ void CSVWorld::EditWidget::remake(int row)
|
|||||||
label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
|
label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
editor->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
if (! (mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable))
|
// HACK: the blocked checkbox needs to keep the same position
|
||||||
|
// FIXME: unfortunately blocked record displays a little differently to unblocked one
|
||||||
|
if (!(mTable->flags (mTable->index (row, i)) & Qt::ItemIsEditable) || i == blockedColumn)
|
||||||
{
|
{
|
||||||
lockedLayout->addWidget (label, locked, 0);
|
lockedLayout->addWidget (label, locked, 0);
|
||||||
lockedLayout->addWidget (editor, locked, 1);
|
lockedLayout->addWidget (editor, locked, 1);
|
||||||
@ -639,7 +646,7 @@ void CSVWorld::EditWidget::remake(int row)
|
|||||||
createEditorContextMenu(editor, display, row);
|
createEditorContextMenu(editor, display, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // Flag_Dialogue_List
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree *tree = static_cast<CSMWorld::IdTree *>(mTable);
|
CSMWorld::IdTree *tree = static_cast<CSMWorld::IdTree *>(mTable);
|
||||||
mNestedTableMapper = new QDataWidgetMapper (this);
|
mNestedTableMapper = new QDataWidgetMapper (this);
|
||||||
@ -686,7 +693,10 @@ void CSVWorld::EditWidget::remake(int row)
|
|||||||
label->setEnabled(false);
|
label->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
createEditorContextMenu(editor, display, row);
|
if (!isBlocked)
|
||||||
|
createEditorContextMenu(editor, display, row);
|
||||||
|
else
|
||||||
|
editor->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i)));
|
mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i)));
|
||||||
|
@ -78,6 +78,8 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptio
|
|||||||
for (std::vector<std::pair<int, QString> >::const_iterator iter (mValues.begin());
|
for (std::vector<std::pair<int, QString> >::const_iterator iter (mValues.begin());
|
||||||
iter!=mValues.end(); ++iter)
|
iter!=mValues.end(); ++iter)
|
||||||
comboBox->addItem (iter->second);
|
comboBox->addItem (iter->second);
|
||||||
|
|
||||||
|
comboBox->setMaxVisibleItems(20);
|
||||||
|
|
||||||
return comboBox;
|
return comboBox;
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,11 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo
|
|||||||
connect (&mData, SIGNAL (idListChanged()), this, SLOT (dataIdListChanged()));
|
connect (&mData, SIGNAL (idListChanged()), this, SLOT (dataIdListChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::GenericCreator::setEditorMaxLength (int length)
|
||||||
|
{
|
||||||
|
mId->setMaxLength (length);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::GenericCreator::setEditLock (bool locked)
|
void CSVWorld::GenericCreator::setEditLock (bool locked)
|
||||||
{
|
{
|
||||||
mLocked = locked;
|
mLocked = locked;
|
||||||
|
@ -84,6 +84,8 @@ namespace CSVWorld
|
|||||||
|
|
||||||
std::string getNamespace() const;
|
std::string getNamespace() const;
|
||||||
|
|
||||||
|
void setEditorMaxLength(int length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void updateNamespace();
|
void updateNamespace();
|
||||||
|
@ -81,6 +81,23 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent,
|
|||||||
CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager();
|
CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager();
|
||||||
CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent);
|
CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent);
|
||||||
editor->setCompleter(completionManager.getCompleter(display).get());
|
editor->setCompleter(completionManager.getCompleter(display).get());
|
||||||
|
|
||||||
|
// The savegame format limits the player faction string to 32 characters.
|
||||||
|
// The region sound name is limited to 32 characters. (ESM::Region::SoundRef::mSound)
|
||||||
|
// The script name is limited to 32 characters. (ESM::Script::SCHD::mName)
|
||||||
|
// The cell name is limited to 64 characters. (ESM::Header::GMDT::mCurrentCell)
|
||||||
|
if (display == CSMWorld::ColumnBase::Display_Faction ||
|
||||||
|
display == CSMWorld::ColumnBase::Display_Sound ||
|
||||||
|
display == CSMWorld::ColumnBase::Display_Script ||
|
||||||
|
display == CSMWorld::ColumnBase::Display_Referenceable)
|
||||||
|
{
|
||||||
|
editor->setMaxLength (32);
|
||||||
|
}
|
||||||
|
else if (display == CSMWorld::ColumnBase::Display_Cell)
|
||||||
|
{
|
||||||
|
editor->setMaxLength (64);
|
||||||
|
}
|
||||||
|
|
||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd
|
|||||||
std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes();
|
std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes();
|
||||||
|
|
||||||
mType = new QComboBox (this);
|
mType = new QComboBox (this);
|
||||||
|
mType->setMaxVisibleItems(20);
|
||||||
|
|
||||||
for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
|
for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
|
||||||
iter!=types.end(); ++iter)
|
iter!=types.end(); ++iter)
|
||||||
{
|
{
|
||||||
@ -31,8 +32,12 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd
|
|||||||
mType->addItem (QIcon (id2.getIcon().c_str()), id2.getTypeName().c_str(),
|
mType->addItem (QIcon (id2.getIcon().c_str()), id2.getTypeName().c_str(),
|
||||||
static_cast<int> (id2.getType()));
|
static_cast<int> (id2.getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mType->model()->sort(0);
|
||||||
|
|
||||||
insertBeforeButtons (mType, false);
|
insertBeforeButtons (mType, false);
|
||||||
|
|
||||||
|
connect (mType, SIGNAL (currentIndexChanged (int)), this, SLOT (setType (int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ReferenceableCreator::reset()
|
void CSVWorld::ReferenceableCreator::reset()
|
||||||
@ -41,6 +46,30 @@ void CSVWorld::ReferenceableCreator::reset()
|
|||||||
GenericCreator::reset();
|
GenericCreator::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ReferenceableCreator::setType (int index)
|
||||||
|
{
|
||||||
|
// container items have name limit of 32 characters
|
||||||
|
std::string text = mType->currentText().toStdString();
|
||||||
|
if (text == "Potion" ||
|
||||||
|
text == "Apparatus" ||
|
||||||
|
text == "Armor" ||
|
||||||
|
text == "Book" ||
|
||||||
|
text == "Clothing" ||
|
||||||
|
text == "Ingredient" ||
|
||||||
|
text == "ItemLevelledList" ||
|
||||||
|
text == "Light" ||
|
||||||
|
text == "Lockpick" ||
|
||||||
|
text == "Miscellaneous" ||
|
||||||
|
text == "Probe" ||
|
||||||
|
text == "Repair" ||
|
||||||
|
text == "Weapon")
|
||||||
|
{
|
||||||
|
GenericCreator::setEditorMaxLength (32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GenericCreator::setEditorMaxLength (32767);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::ReferenceableCreator::cloneMode (const std::string& originId,
|
void CSVWorld::ReferenceableCreator::cloneMode (const std::string& originId,
|
||||||
const CSMWorld::UniversalId::Type type)
|
const CSMWorld::UniversalId::Type type)
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,9 @@ namespace CSVWorld
|
|||||||
|
|
||||||
void toggleWidgets(bool active = true) override;
|
void toggleWidgets(bool active = true) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void setType (int index);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user