Compare commits

...

52 Commits

Author SHA1 Message Date
Qiuzhizhe
00db9f6602 Fix ItemActor::getItemStack() crash 2023-04-08 21:45:41 -07:00
Qiuzhizhe
acc469d6b2 Release v408.3.1 2023-03-26 07:00:35 -07:00
Qiuzhizhe
ac7733eeee Fix 指令在无作弊情况下不能使用 2023-03-26 06:50:43 -07:00
Qiuzhizhe
3159677ba0 Fix AuToTooth 2023-03-22 07:45:40 -07:00
Qiuzhizhe
d46e111e8d Release v408.3.0 2023-03-22 01:56:04 -07:00
Qiuzhizhe
a5080d62ee 添加自动提交Tooth脚本 2023-03-22 01:53:27 -07:00
Qiuzhizhe
bcf199e8d2 修正HitResult::getEntity函数 2023-03-20 07:03:22 -07:00
Qiuzhizhe
f4a3110d8f 修复SetDisplayObjectivePacket 2023-03-20 07:02:37 -07:00
Qiuzhizhe
6bd4535330 添加Potion::PotionTypePotion::PotionVariant成员 2023-03-20 07:02:14 -07:00
Qiuzhizhe
3f189db4ae 修复TransferPacket 2023-03-20 07:00:16 -07:00
Qiuzhizhe
683b6fd589 修复SetScorePacket 2023-03-20 06:59:39 -07:00
Qiuzhizhe
aa5fbcb521 粗心,漏和多写符号 2023-03-20 06:06:44 -07:00
Qiuzhizhe
70fc659ba2 去掉无用代码 2023-03-18 06:41:56 -07:00
Qiuzhizhe
b3c3b76551 修复ProjectileSpawn事件 2023-03-18 06:41:14 -07:00
Qiuzhizhe
4097c5417f 修复ProjectileHitEntity事件 2023-03-18 06:40:27 -07:00
Qiuzhizhe
84287a4e3a 修复MobHurt事件 2023-03-18 06:40:07 -07:00
Qiuzhizhe
e48832d224 修改遗漏的偏移量 2023-03-18 06:39:01 -07:00
Qiuzhizhe
1f2e7e5516 修复ProjectileHitBlock事件 2023-03-18 06:37:40 -07:00
Qiuzhizhe
d4632e915f 修复ContainerChange事件,可能有问题 2023-03-18 06:37:12 -07:00
Qiuzhizhe
b14f5fe505 修复BlockExploded事件 2023-03-18 06:36:37 -07:00
Qiuzhizhe
a73afd9fe9 修复PlayerDropItem事件 2023-03-18 06:35:08 -07:00
Qiuzhizhe
62950cbd21 部分补全LevelContainerModel 2023-03-18 06:33:39 -07:00
Qiuzhizhe
ac4ca933de 补全HitResult 2023-03-18 06:33:20 -07:00
Qiuzhizhe
68fe280544 补全Explosion 2023-03-17 22:30:48 -07:00
Qiuzhizhe
1d9372749e add ActorBlockSyncMessage 2023-03-17 22:30:13 -07:00
Qiuzhizhe
f24c726a81 规范Event里的变量命名 2023-03-17 22:29:15 -07:00
Qiuzhizhe
70f0717b59 大意了,没留意到SDK是没有ll头的 2023-03-06 07:19:50 -08:00
Qiuzhizhe
7007106d39 把偏移量集中 2023-03-05 00:33:15 -08:00
Qiuzhizhe
6d752996a5 Fix push SDK 2023-03-03 18:40:40 -08:00
Qiuzhizhe
e723c6c4cb Release v408.2.0 2023-03-03 11:22:28 -08:00
Qiuzhizhe
a582e254e2 change readme 2023-03-03 10:32:08 -08:00
Qiuzhizhe
690132ce0f 根据LL重构文件结构 2023-03-03 10:18:21 -08:00
Qiuzhizhe
125df0725f Fix AttributeInstance class 2023-02-27 22:50:09 -08:00
Qiuzhizhe
dafaa3d8a5 Push Release v408.1.0 2023-02-11 22:16:46 -08:00
Qiuzhizhe
0b5cb1e186 Fix mce::UUID::isEmpty() 2023-02-11 21:35:51 -08:00
Qiuzhizhe
67688fe8e7 Level::BlockPalettePtr replace Level::BlockPalette 2023-02-09 23:03:14 -08:00
Qiuzhizhe
bcd2a1f717 Fix WitherBossDestroy Event 2023-02-09 01:50:49 -08:00
Qiuzhizhe
951c5e1f7d Fix Form System 2023-02-09 01:50:49 -08:00
quizhizhe
e31b6bd4e9 Change the version number format 2023-02-07 16:10:46 +08:00
Qiuzhizhe
9659c65121 Fix BlockLegacy::getBlockItemId() 2023-02-05 06:40:19 -08:00
Qiuzhizhe
0070831a52 Fix CompoundTag::fromBlock(Block* block) 2023-02-05 06:39:52 -08:00
Qiuzhizhe
e277252a1d Fix AABB::getCenter() 2023-02-03 18:22:08 -08:00
Qiuzhizhe
7a597c698e
替换偏移获取 2023-02-04 01:04:44 +08:00
Qiuzhizhe
adbb5bd375
添加WE缺失的文件 2023-02-04 01:03:36 +08:00
Qiuzhizhe
e6bbddafa5
补全Actor类 2023-02-04 01:01:08 +08:00
Qiuzhizhe
4724039c32
Merge remote-tracking branch 'origin/main' into main 2023-02-02 14:38:16 +08:00
Qiuzhizhe
4ee7f71968
Fix BlockSource::getDimensionId 2023-02-02 14:37:11 +08:00
quizhizhe
2720690163 remove not use action 2023-01-08 09:02:17 +08:00
Qiuzhizhe
7332bc36c7
Add Level::getPlayer(mce::UUID) 2022-11-17 14:37:18 +08:00
Qiuzhizhe
71bb904d81
Add Command::getPlayerFromOrigin 2022-11-17 14:36:23 +08:00
Qiuzhizhe
85911a26b6
Fix mce::UUID::isEmpty 2022-11-17 14:35:26 +08:00
Qiuzhizhe
08b1967cc3
Add Player::getClientUUID 2022-11-17 14:34:27 +08:00
4237 changed files with 32373 additions and 26309 deletions

View File

@ -1,55 +1,53 @@
# Documents: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
Language: Cpp
# BasedOnStyle: LLVM
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignOperands: Align
AlwaysBreakTemplateDeclarations : true
AlwaysBreakTemplateDeclarations: Yes
AlignTrailingComments: true
AllowAllArgumentsOnNextLine : true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine : true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: All
AllowShortEnumsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
BinPackArguments: true
BinPackParameters: true
ConstructorInitializerIndentWidth: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ColumnLimit: 0
BreakBeforeConceptDeclarations: Always
RequiresClausePosition: OwnLine
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
PointerAlignment: Left
IndentWidth: 4
SortIncludes: false
SortIncludes: Never
MaxEmptyLinesToKeep: 2
SpacesInSquareBrackets: false
SpacesInParentheses : false
SpacesInParentheses: false
SpaceBeforeAssignmentOperators: true
SpacesInContainerLiterals: true
IndentWrappedFunctionNames: true
KeepEmptyLinesAtTheStartOfBlocks: true
SeparateDefinitionBlocks: Always
BreakConstructorInitializersBeforeComma: true
SpaceAfterCStyleCast: false
IndentCaseLabels: true
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
# case 语句后面
AfterCaseLabel: false
# class定义后面
AfterClass: false
# 控制语句后面
AfterControlStatement: false
# enum定义后面
AfterEnum: false
# 函数定义后面

4
.clangd Normal file
View File

@ -0,0 +1,4 @@
Diagnostics:
Suppress: ["-Wmicrosoft-enum-forward-reference", "-Wc++11-narrowing"]
CompileFlags:
Add: ["-ferror-limit=0", "-D__FUNCTION__=\"dummy\"", "-D_CRT_USE_BUILTIN_OFFSETOF"]

194
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,194 @@
name: Build
on:
workflow_dispatch:
pull_request:
push:
env:
BUILD_TYPE: Release
jobs:
build:
name: Build
# runs-on: self-hosted
runs-on: windows-2022
steps:
- name: Checkout repository
uses: actions/checkout@v3.2.0
with:
fetch-depth: 1
submodules: 'true'
- name: Cache BDS libraries
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('scripts/LINK.txt') }}
- name: Download BDS if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build libraries if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
mkdir ..\LiteLoader\lib
move bedrock_server_api.lib ..\LiteLoader\lib
move bedrock_server_var.lib ..\LiteLoader\lib
shell: cmd
- name: Get short SHA
id: sha_short
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set LITELOADER_VERSION_COMMIT_SHA
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_COMMIT_SHA\s+.*/#define LITELOADER_VERSION_COMMIT_SHA ${{ steps.sha_short.outputs.sha_short }}\r/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Configure CMake (MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build all
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Pack output
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackOutput
shell: cmd
- name: Pack SDK on push event
if: github.event_name == 'push'
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackSDK
shell: cmd
- name: Configure CMake (ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Compress resource packs for LiteLoaderBDS CUI on push event
if: github.event_name == 'push'
run: |
cd build/output/plugins/LiteLoader/ResourcePacks
7z a LiteLoaderBDS-CUI.tar LiteLoaderBDS-CUI
rm -r LiteLoaderBDS-CUI
shell: bash
- name: Update C++ SDK on push event
if: github.event_name == 'push'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
cd scripts
./UploadSDK.cmd action
env:
REPO_KEY: ${{secrets.PUSH_TOKEN}}
USERNAME: github-actions[bot]
shell: cmd
# - name: Download LLMoney
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# git clone https://github.com/Tooth-Hub/LLMoney.git LLMoney-bin
# cp LLMoney-bin/LLMoney.dll build/output/plugins/
# shell: bash
- name: Upload LiteLoaderBDS
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoaderBDS
path: |
${{ github.workspace }}\build\output\LLPeEditor.exe
${{ github.workspace }}\build\output\LLPreLoader.dll
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
# ${{ github.workspace }}\build\output\plugins\LLMoney.dll
- name: Upload PeEditor
uses: actions/upload-artifact@v3.1.0
with:
name: PeEditor
path: ${{ github.workspace }}\build\output\LLPeEditor.exe
- name: Upload PreLoader
uses: actions/upload-artifact@v3.1.0
with:
name: PreLoader
path: ${{ github.workspace }}\build\output\LLPreLoader.dll
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: |
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\*.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
- name: Upload ScriptEngine
uses: actions/upload-artifact@v3.1.0
with:
name: ScriptEngine
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\lib\node_modules.tar
${{ github.workspace }}\build\output\plugins\lib\package.json
- name: Upload LLParticle
uses: actions/upload-artifact@v3.1.0
with:
name: LLParticle
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
- name: Upload LLPermission
uses: actions/upload-artifact@v3.1.0
with:
name: LLPermission
path: ${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
- name: Upload PDB files
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\build\pdb\

View File

@ -1,189 +0,0 @@
#name: CMake(self-hosted)
#
#on:
# push:
# paths:
# - '**.cpp'
# - '**.cc'
# - '**.cxx'
# - '**.c'
# - '**.hpp'
# - '**.hh'
# - '**.hxx'
# - '**.h'
# - '.github/workflows/cmake-self-hosted.yml'
# - '**/CMakeLists.txt'
#
#env:
# BUILD_TYPE: Release
#
#jobs:
# build:
# runs-on: self-hosted
#
# steps:
# - uses: actions/checkout@v3.0.2
# with:
# fetch-depth: 1
# submodules: 'true'
#
# - name: Cache Bedrock Dedicated Server Library
# id: cache-bds-lib
# uses: actions/cache@v3
# env:
# cache-name: cache-bds-lib
# with:
# path: |
# ${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
# ${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
# key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('Scripts/LINK.txt') }}
#
# - name: Download Server
# if: steps.cache-bds-lib.outputs.cache-hit != 'true'
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# mkdir Tools/Server
# ServerLink=$(cat 'Scripts/LINK.txt')
# curl -L -o Tools/Server/server.zip "$ServerLink"
# unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
# shell: bash
#
# - name: Build Library
# if: steps.cache-bds-lib.outputs.cache-hit != 'true'
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# cd Tools
# LibraryBuilder.exe Server
# shell: cmd
#
# - name: Change LITELOADER_VERSION_STATUS_BETA
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# if: false == startsWith(github.ref, 'refs/tags/')
# run: |
# sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_BETA/' LiteLoader/Main/Version.h
# sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
# cat LiteLoader/Main/Version.h
# shell: bash
#
# - name: Change LITELOADER_VERSION_STATUS_RELEASE
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# if: startsWith(github.ref, 'refs/tags/')
# run: |
# sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_RELEASE/' LiteLoader/Main/Version.h
# sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
# shell: bash
#
# - name: Get MSVC Path
# working-directory: E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\
# run: echo "MSVC_VER=$(ls | tail -n 1)" >> $GITHUB_ENV
# shell: bash
#
# #- name: Configure CMake(MSVC)
# # run: |
# # set CC="E:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/${{env.MSVC_VER}}/bin/Hostx64/x64/cl.exe"
# # "E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 & cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -G Ninja -DCMAKE_TRY_COMPILE_TARGET_TYPE="STATIC_LIBRARY" -DCMAKE_MAKE_PROGRAM="E:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\2022\Community\COMMON7\IDE\COMMONEXTENSIONS\Microsoft\CMake\Ninja\ninja.exe"
# # shell: cmd
#
# #- name: Build
# # run: |
# # "E:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 & cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
# # shell: cmd
#
# - name: Configure CMake(MSVC)
# run: |
# cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
# shell: cmd
#
# - name: Build
# run: |
# cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
# shell: cmd
#
# - name: Configure CMake(ClangCL)
# run: |
# cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
# shell: cmd
#
# - name: Build SymDBHelper
# run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
#
# - name: Compress Resource Packs
# run: |
# cd RELEASE/plugins/LiteLoader/ResourcePacks
# 7z a LiteLoaderBDS-CUI.tar LiteLoaderBDS-CUI
# rm -r LiteLoaderBDS-CUI
# shell: bash
#
# - name: Pack Release
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# cd Scripts
# ./PackRelease.cmd action
# shell: cmd
#
# - name: Move PDB to path
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# mkdir PDB
# cp x64/Release/*.pdb PDB
# shell: bash
#
# - name: Pack PDB
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# if: startsWith(github.ref, 'refs/tags/')
# run: 7z a -tzip PDB.zip PDB
# shell: bash
#
# - name: Update LiteLoaderSDK
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# git config --global user.name "github-actions[bot]"
# git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
# cd Scripts
# ./UploadSDK.cmd action
# env:
# REPO_KEY: ${{secrets.PUSH_TOKEN}}
# USERNAME: github-actions[bot]
# shell: cmd
#
# - name: Upload LiteLoader
# uses: actions/upload-artifact@v3.1.0
# with:
# name: LiteLoader
# path: ${{ github.workspace }}\RELEASE\
#
# - name: Upload PDB
# uses: actions/upload-artifact@v3.1.0
# with:
# name: PDB
# path: ${{ github.workspace }}\PDB
#
# - name: Prepare for creating Release
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# id: rel
# if: startsWith(github.ref, 'refs/tags/')
# run: |
# echo ::set-output name=tag::${GITHUB_REF#refs/*/}
# mv LiteLoader.zip LiteLoader-${GITHUB_REF#refs/*/}.zip
# shell: bash
#
# - name: Create New Release
# uses: softprops/action-gh-release@v0.1.14
# if: startsWith(github.ref, 'refs/tags/')
# with:
# body_path: ${{ github.workspace }}\CHANGELOG.md
# files: |
# ${{ github.workspace }}\LiteLoader-${{ steps.rel.outputs.tag }}.zip
# ${{ github.workspace }}\PDB.zip
# env:
# GITHUB_REPOSITORY: LiteLDev/LiteLoaderBDS
#
# #- name: Publish to MineBBS
# # working-directory: ${{ env.GITHUB_WORKSPACE }}
# # if: startsWith(github.ref, 'refs/tags/')
# # run: |
# # curl -X POST https://api.github.com/repos/LiteLDev/AutoUpdate-MineBBS/dispatches \
# # -H "Accept: application/vnd.github.everest-preview+json" \
# # -H "Authorization: Bearer ${{ secrets.MB_TOKEN }}" \
# # --data '{"event_type": "webhook"}'
# # shell: bash

View File

@ -1,143 +0,0 @@
name: CMake
on:
push:
paths:
- '**.cpp'
- '**.cc'
- '**.cxx'
- '**.c'
- '**.hpp'
- '**.hh'
- '**.hxx'
- '**.h'
- '.github/workflows/cmake.yml'
- '**/CMakeLists.txt'
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: windows-2022
steps:
- uses: actions/checkout@v3.0.2
with:
fetch-depth: 1
#submodules: 'true'
- name: Cache Bedrock Dedicated Server Library
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('Scripts/LINK.txt') }}
- name: Download Server
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'Scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build Library
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
shell: cmd
- name: Change LITELOADER_VERSION_STATUS_BETA
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: false == startsWith(github.ref, 'refs/tags/')
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_BETA/' LiteLoader/Main/Version.h
sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
cat LiteLoader/Main/Version.h
shell: bash
- name: Change LITELOADER_VERSION_STATUS_RELEASE
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: startsWith(github.ref, 'refs/tags/')
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_RELEASE/' LiteLoader/Main/Version.h
sed -r -i 's/#define\s+LITELOADER_VERSION_ACTIONS\s+.*/#define LITELOADER_VERSION_ACTIONS ${{ github.run_number }}\r/' LiteLoader/Main/Version.h
shell: bash
- name: Get MSVC Path
working-directory: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\
run: echo "MSVC_VER=$(ls | tail -n 1)" >> $GITHUB_ENV
shell: bash
- name: Configure CMake(MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Configure CMake(ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Pack Release
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Scripts
./PackRelease.cmd action
shell: cmd
- name: Move PDB to path
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir PDB
cp x64/Release/*.pdb PDB
shell: bash
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: ${{ github.workspace }}\RELEASE\
- name: Upload PDB
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\PDB
- name: Prepare for creating Release
working-directory: ${{ env.GITHUB_WORKSPACE }}
id: rel
if: startsWith(github.ref, 'refs/tags/')
run: |
echo ::set-output name=tag::${GITHUB_REF#refs/*/}
mv LiteLoader.zip LiteLoader-${GITHUB_REF#refs/*/}.zip
shell: bash
- name: Create New Release
uses: softprops/action-gh-release@v0.1.14
if: startsWith(github.ref, 'refs/tags/')
with:
body_path: ${{ github.workspace }}\CHANGELOG.md
files: |
${{ github.workspace }}\LiteLoader-${{ steps.rel.outputs.tag }}.zip
${{ github.workspace }}\PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40

View File

@ -1,19 +0,0 @@
name: Issue Close Require
on:
schedule:
- cron: "0 0 * * *"
jobs:
issue-close-require:
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v2
with:
actions: 'close-issues'
labels: 'status: more information needed'
inactive-day: 30
body: |
您超过 30 天未反馈信息,我们将关闭该 issue如有需求您可以重新打开或者提交新的 issue。
If you haven't provided feedback for more than 30 days, we will close the issue. You can reopen or submit a new issue if necessary.

View File

@ -1,16 +0,0 @@
name: Issue Close Check
on:
issues:
types: [closed]
jobs:
issue-close-remove-labels:
runs-on: ubuntu-latest
steps:
- name: Remove labels
uses: actions-cool/issues-helper@v2
if: ${{ !github.event.issue.pull_request }}
with:
actions: 'remove-labels'
labels: 'status: need review,status: more information needed'

View File

@ -1,38 +0,0 @@
on:
issue_comment:
types: [created]
name: Add issues workflow labels
jobs:
add-label-if-is-author:
runs-on: ubuntu-latest
if: (github.event.issue.user.id == github.event.comment.user.id) && !github.event.issue.pull_request && (github.event.issue.state == 'open')
steps:
- name: Add require handle label
uses: actions-cool/issues-helper@v2
with:
actions: 'add-labels'
labels: 'status: need review'
- name: Remove require reply label
uses: actions-cool/issues-helper@v2
with:
actions: 'remove-labels'
labels: 'status: more information needed'
add-label-if-not-author:
runs-on: ubuntu-latest
if: (github.event.issue.user.id != github.event.comment.user.id) && !github.event.issue.pull_request && (github.event.issue.state == 'open')
steps:
- name: Add require replay label
uses: actions-cool/issues-helper@v2
with:
actions: 'add-labels'
labels: 'status: more information needed'
- name: Remove require handle label
uses: actions-cool/issues-helper@v2
with:
actions: 'remove-labels'
labels: 'status: need review'

View File

@ -1,16 +0,0 @@
name: Issue Open Check
on:
issues:
types: [opened]
jobs:
issue-open-add-labels:
runs-on: ubuntu-latest
steps:
- name: Add labels
uses: actions-cool/issues-helper@v2
if: ${{ !github.event.issue.pull_request }}
with:
actions: 'add-labels'
labels: 'status: need review'

281
.github/workflows/publish_release.yml vendored Normal file
View File

@ -0,0 +1,281 @@
name: Release
on:
workflow_dispatch:
inputs:
tag:
required: true
description: 'Release Tag'
status:
required: true
description: 'Release Status (beta, stable)'
env:
BUILD_TYPE: Release
jobs:
build:
name: Build
runs-on: windows-2022
steps:
- name: Checkout repository
uses: actions/checkout@v3.2.0
with:
fetch-depth: 1
submodules: 'true'
- name: Create tag
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag | xargs git tag -d
git tag ${{ github.event.inputs.tag }}
git push origin ${{ github.event.inputs.tag }}
shell: bash
- name: Cache BDS libraries
id: cache-bds-lib
uses: actions/cache@v3
env:
cache-name: cache-bds-lib
with:
path: |
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_api.lib
${{ env.GITHUB_WORKSPACE }}LiteLoader/Lib/bedrock_server_var.lib
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('scripts/LINK.txt') }}
- name: Download BDS if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
mkdir Tools/Server
ServerLink=$(cat 'scripts/LINK.txt')
curl -L -o Tools/Server/server.zip "$ServerLink"
unzip Tools/Server/server.zip -d Tools/Server/ > /dev/null
shell: bash
- name: Build libraries if not cached
if: steps.cache-bds-lib.outputs.cache-hit != 'true'
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
cd Tools
LibraryBuilder.exe Server
mkdir ..\LiteLoader\lib
move bedrock_server_api.lib ..\LiteLoader\lib
move bedrock_server_var.lib ..\LiteLoader\lib
shell: cmd
- name: Get short SHA
id: sha_short
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set LITELOADER_VERSION_COMMIT_SHA
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_COMMIT_SHA\s+.*/#define LITELOADER_VERSION_COMMIT_SHA ${{ steps.sha_short.outputs.sha_short }}\r/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Set LITELOADER_VERSION_STATUS_BETA
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: github.event.inputs.status == 'beta'
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_BETA/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Set LITELOADER_VERSION_STATUS_RELEASE
working-directory: ${{ env.GITHUB_WORKSPACE }}
if: github.event.inputs.status == 'stable'
run: |
sed -r -i 's/#define\s+LITELOADER_VERSION_STATUS\s+LITELOADER_VERSION_\w+/#define LITELOADER_VERSION_STATUS LITELOADER_VERSION_RELEASE/' LiteLoader/include/liteloader/Version.h
shell: bash
- name: Configure CMake (MSVC)
run: |
cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
shell: cmd
- name: Build all
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
shell: cmd
- name: Pack output
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackOutput
shell: cmd
- name: Pack SDK
run: |
cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target PackSDK
shell: cmd
- name: Configure CMake (ClangCL)
run: |
cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T clangcl
shell: cmd
- name: Build SymDBHelper
run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} --target SymDBHelper
- name: Compress resource packs for LiteLoaderBDS
run: |
cd build/output/plugins/LiteLoader/ResourcePacks
7z a LiteLoaderBDS-CUI.tar LiteLoaderBDS-CUI
rm -r LiteLoaderBDS-CUI
shell: bash
- name: Update C++ SDK
working-directory: ${{ env.GITHUB_WORKSPACE }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
cd scripts
./UploadSDK.cmd action release
env:
REPO_KEY: ${{secrets.PUSH_TOKEN}}
USERNAME: github-actions[bot]
shell: cmd
# - name: Download LLMoney
# working-directory: ${{ env.GITHUB_WORKSPACE }}
# run: |
# git clone https://github.com/Tooth-Hub/LLMoney.git LLMoney-bin
# cp LLMoney-bin/LLMoney.dll build/output/plugins/
# shell: bash
- name: Upload LiteLoaderBDS
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoaderBDS
path: |
${{ github.workspace }}\build\output\LLPeEditor.exe
${{ github.workspace }}\build\output\LLPreLoader.dll
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
# ${{ github.workspace }}\build\output\plugins\LLMoney.dll
- name: Upload PeEditor
uses: actions/upload-artifact@v3.1.0
with:
name: PeEditor
path: ${{ github.workspace }}\build\output\LLPeEditor.exe
- name: Upload PreLoader
uses: actions/upload-artifact@v3.1.0
with:
name: PreLoader
path: ${{ github.workspace }}\build\output\LLPreLoader.dll
- name: Upload LiteLoader
uses: actions/upload-artifact@v3.1.0
with:
name: LiteLoader
path: |
${{ github.workspace }}\build\output\LiteLoader.dll
${{ github.workspace }}\build\output\plugins\lib\*.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LangPack\
${{ github.workspace }}\build\output\plugins\LiteLoader\7z\
${{ github.workspace }}\build\output\plugins\LiteLoader\CrashLogger_Daemon.exe
- name: Upload ScriptEngine
uses: actions/upload-artifact@v3.1.0
with:
name: ScriptEngine
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Js.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.Lua.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\LiteLoader.NodeJs.dll
${{ github.workspace }}\build\output\plugins\lib\node_modules.tar
${{ github.workspace }}\build\output\plugins\lib\package.json
- name: Upload LLParticle
uses: actions/upload-artifact@v3.1.0
with:
name: LLParticle
path: |
${{ github.workspace }}\build\output\plugins\LiteLoader\ParticleAPI.dll
${{ github.workspace }}\build\output\plugins\LiteLoader\ResourcePacks\LiteLoaderBDS-CUI.tar
- name: Upload LLPermission
uses: actions/upload-artifact@v3.1.0
with:
name: LLPermission
path: ${{ github.workspace }}\build\output\plugins\LiteLoader\PermissionAPI.dll
- name: Upload PDB files
uses: actions/upload-artifact@v3.1.0
with:
name: PDB
path: ${{ github.workspace }}\build\pdb\
publish_release:
name: Publish release
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Download artifacts
uses: actions/download-artifact@v3
with:
path: build/
- name: Push Tooth
working-directory: ${{env.GITHUB_WORKSPACE}}
if: github.event.inputs.status == 'stable'
run: |
cd Scripts
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
chmod +x ./UploadTooth.sh
./UploadTooth.sh ${{ github.event.inputs.tag }}
env:
REPO_KEY: ${{secrets.PUSH_TOKEN}}
USERNAME: github-actions[bot]
shell: bash
- name: Pack artifacts
run: |
cd build/
zip -9r LiteLoaderBDS-${{ github.event.inputs.tag }}.zip LiteLoaderBDS/*
zip -9r PDB.zip PDB/*
zip -9r Modules.zip PeEditor PreLoader LiteLoader ScriptEngine LLParticle LLPermission
shell: bash
- name: Create release
if: github.event.inputs.status == 'stable'
uses: ncipollo/release-action@v1
with:
prerelease: false
tag: ${{ github.event.inputs.tag }}
bodyFile: RELEASE_NOTES.md
artifacts: |
build/LiteLoaderBDS-${{ github.event.inputs.tag }}.zip
build/Modules.zip
build/PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40
- name: Create pre-release
if: github.event.inputs.status != 'stable'
uses: ncipollo/release-action@v1
with:
prerelease: true
tag: ${{ github.event.inputs.tag }}
bodyFile: RELEASE_NOTES.md
artifacts: |
build/Modules.zip
build/PDB.zip
env:
GITHUB_REPOSITORY: quizhizhe/LiteLoaderBDS-1.16.40

6
.gitignore vendored
View File

@ -7,7 +7,7 @@
**/bedrock_server_api.lib
**/bedrock_server_var.lib
**/SymDB_DelayLoadHelper.lib
LiteLoader/Lib/SymDBHelper.lib
LiteLoader/lib/SymDBHelper.lib
**/*.lastcodeanalysissucceeded
*.zip
@ -27,8 +27,8 @@ RELEASE/plugins/LiteLoader/pdb
cmake-build-release/
/out
LiteLoader/Lib/Demangler.pdb
LiteLoader/Lib/Demangler.lib
LiteLoader/lib/Demangler.pdb
LiteLoader/lib/Demangler.lib
/build
**/Directory.build.props

10
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "RELEASE/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI"]
path = RELEASE/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI
[submodule "assets/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI"]
path = assets/plugins/LiteLoader/ResourcePacks/LiteLoaderBDS-CUI
url = https://github.com/OEOTYAN/LiteLoaderBDS-CUI.git
[submodule "ParticleAPI-1.16.40"]
path = ParticleAPI-1.16.40
url = https://github.com/quizhizhe/ParticleAPI-1.16.40
[submodule "PermissionAPI-1.16.40"]
path = PermissionAPI-1.16.40
url = https://github.com/quizhizhe/PermissionAPI-1.16.40

View File

@ -1,5 +0,0 @@
## [LiteLoader Release Note]
LiteLoaderBDS-2.6.2-1.16.40 update has been released, adapted 1.16.40.02, ProtocolVersion 408
## [Fix]
- Fix dynamicCommand

8
CMake/CleanOutput.cmake Normal file
View File

@ -0,0 +1,8 @@
add_custom_target(
CleanOutput
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/output
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/pdb
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/sdk
COMMENT "Cleaning output/pdb/sdk directory"
VERBATIM
)

29
CMake/PackOutput.cmake Normal file
View File

@ -0,0 +1,29 @@
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/pdb)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/output)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/output/plugins/LiteLoader/)
add_custom_target(PackOutput)
# Copy assets to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/plugins ${CMAKE_BINARY_DIR}/output/plugins/
COMMENT "Copying assets to output"
VERBATIM
)
# Copy ScriptEngine BaseLib to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/ScriptEngine/assets ${CMAKE_BINARY_DIR}/output/plugins/lib/
COMMENT "Copying ScriptEngine BaseLib to output"
VERBATIM
)
# Copy LLPeEditor to output after build all.
add_custom_command(
TARGET PackOutput POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LLPeEditor.exe ${CMAKE_BINARY_DIR}/output/
COMMENT "Copying LLPeEditor to output"
VERBATIM
)

20
CMake/PackSDK.cmake Normal file
View File

@ -0,0 +1,20 @@
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/include)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/include/llapi)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/tools)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/sdk/lib)
add_custom_target(PackSDK)
add_custom_command(
TARGET PackSDK POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LiteLoader_SOURCE_DIR}/include/llapi ${CMAKE_BINARY_DIR}/sdk/include/llapi
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LiteLoader_SOURCE_DIR}/third-party/include ${CMAKE_BINARY_DIR}/sdk/include
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LibraryBuilder.exe ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/LLPeEditor.exe ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-submodule-add.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-submodule-update.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Tools/SDK-subtree.cmd ${CMAKE_BINARY_DIR}/sdk/tools/
COMMENT "Copying SDK files"
VERBATIM
)

View File

@ -1,14 +1,25 @@
cmake_minimum_required(VERSION 3.21)
project(LL-Parent)
project(LiteLoaderBDS)
set(LiteLoader_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LiteLoader)
set(Demangler_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Tools/Demangler)
set(SCRIPTENGINE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/ScriptEngine)
set(SCRIPTX_SOURCE_DIR ${CMAKE_SOURCE_DIR}/ScriptX)
# Add sub directories
add_subdirectory(PreLoader)
add_subdirectory(LLPreLoader)
add_subdirectory(LiteLoader)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-Lua)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-QuickJs)
add_subdirectory(ScriptEngine/CMake/ScriptEngine-NodeJs)
add_subdirectory(Tools/Demangler)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-Lua)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-QuickJs)
add_subdirectory(ScriptEngine/third-party/ScriptX/CMake/ScriptX-NodeJs)
add_subdirectory(Tools/SymDBHelper)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-Lua)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-QuickJs)
add_subdirectory(Tools/ScriptX/CMake/ScriptX-NodeJs)
add_subdirectory(Tools/SymDBHelper)
add_subdirectory(ParticleAPI-1.16.40)
add_subdirectory(PermissionAPI-1.16.40/PermissionAPI)
include(${CMAKE_SOURCE_DIR}/CMake/PackOutput.cmake)
include(${CMAKE_SOURCE_DIR}/CMake/PackSDK.cmake)
include(${CMAKE_SOURCE_DIR}/CMake/CleanOutput.cmake)

View File

@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.21)
project(LLPreLoader)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
add_definitions(-D"NDEBUG" -D"_WINDOWS" -D"_USRDLL" -D"_WINDLL" -D"_UNICODE" -D"UNICODE")
add_compile_options(
/permissive- /GS /GL /W0 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise
/errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /EHsc /nologo /diagnostics:column
)
add_link_options(
/MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO
/SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
)
aux_source_directory(${PROJECT_SOURCE_DIR}/third-party/rawpdb DIR_LIB_SRCS)
aux_source_directory(${PROJECT_SOURCE_DIR}/src PROJECT_SRCS)
aux_source_directory(${PROJECT_SOURCE_DIR}/include PROJECT_INCLUDES)
add_library(LLPreLoader SHARED ${PROJECT_INCLUDES} ${PROJECT_SRCS} ${DIR_LIB_SRCS})
target_link_libraries(
LLPreLoader SymDBHelper Demangler
"${LiteLoader_SOURCE_DIR}/third-party/lib/detours/detours.lib"
)
target_include_directories(
LLPreLoader
PRIVATE ${LiteLoader_SOURCE_DIR}/include
PRIVATE ${LiteLoader_SOURCE_DIR}/third-party/include
PRIVATE ${PROJECT_SOURCE_DIR}/include
PRIVATE ${PROJECT_SOURCE_DIR}/third-party
PRIVATE ${Demangler_SOURCE_DIR}/include
)
# Copy the dll and pdb to the output directory
add_custom_command(
TARGET LLPreLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LLPreLoader> ${CMAKE_BINARY_DIR}/output/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PDB_FILE:LLPreLoader> ${CMAKE_BINARY_DIR}/pdb/
COMMENT "Copying dll and pdb to output directory"
VERBATIM
)

View File

@ -2,7 +2,7 @@
#include <optional>
#include <string>
#include "../Tools/Demangler/include/MicrosoftDemangle.h"
#include "MicrosoftDemangle.h"
namespace FakeSymbol {

View File

@ -2,12 +2,12 @@
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include "../LiteLoader/Header/third-party/FMT/chrono.h"
#include "../LiteLoader/Header/third-party/FMT/color.h"
#include "../LiteLoader/Header/third-party/FMT/core.h"
#include "../LiteLoader/Header/third-party/FMT/os.h"
#include "../LiteLoader/Header/third-party/FMT/format.h"
#include "../LiteLoader/Header/third-party/Nlohmann/json.hpp"
#include "FMT/chrono.h"
#include "FMT/color.h"
#include "FMT/core.h"
#include "FMT/os.h"
#include "FMT/format.h"
#include "Nlohmann/json.hpp"
#include <string>
#include <filesystem>
#include <fstream>

View File

@ -9,7 +9,7 @@
#endif
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <Windows.h>
#include <filesystem>
#include <fstream>
#include <iostream>

View File

@ -1,9 +1,9 @@
#include "pch.h"
#include "Logger.h"
#include "../include/pch.h"
#include "../include/Logger.h"
#include <string>
#include <set>
#include <filesystem>
#include <windows.h>
#include <Windows.h>
using std::string;
using std::wstring;

View File

@ -1,4 +1,4 @@
#include "pch.h"
#include "../include/pch.h"
#include <cstdio>
#include <filesystem>
#include <fstream>
@ -10,22 +10,22 @@
#include <vector>
#include <mutex>
#include "../LiteLoader/Header/Utils/Hash.h"
#include "../LiteLoader/Header/third-party/detours/detours.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_RawFile.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_InfoStream.h"
#include "../LiteLoader/Lib/third-party/rawpdb/PDB_DBIStream.h"
#include "../LiteLoader/Lib/third-party/rawpdb/Foundation/PDB_DisableWarningsPop.h"
#include "llapi/utils/Hash.h"
#include "detours/detours.h"
#include "rawpdb/PDB.h"
#include "rawpdb/PDB_RawFile.h"
#include "rawpdb/PDB_InfoStream.h"
#include "rawpdb/PDB_DBIStream.h"
#include "rawpdb/Foundation/PDB_DisableWarningsPop.h"
#include "../LiteLoader/Header/third-party/parallel_hashmap/phmap.h"
#include "parallel_hashmap/phmap.h"
#include "Logger.h"
#include "../LiteLoader/Header/third-party/FMT/printf.h"
#include "FMT/printf.h"
#include <iomanip>
#include "Utils.h"
#include "FakeSymbol.hpp"
#include "../include/FakeSymbol.hpp"
using std::list;
using std::string, std::string_view;

View File

@ -1,5 +1,5 @@
#include "pch.h"
#include "Utils.h"
#include "../include/pch.h"
#include "../include/Utils.h"
#include <Psapi.h>
std::string GetCallerModuleFileName(unsigned long FramesToSkip) {
static const int maxFrameCount = 1;

View File

@ -1,6 +1,6 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "Logger.h"
#include "../include/pch.h"
#include "../include/Logger.h"
void fixUpLibDir();
void loadDlls();
#pragma comment(linker, "/export:GetServerSymbol=LLPreLoader.dlsym_real")

View File

@ -2,4 +2,4 @@
/cmake-build-release/
/cmake-build-debug/
/.idea/
Lib/LiteLoader.lib
lib/LiteLoader.lib

View File

@ -4,67 +4,90 @@ project(LiteLoader)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Release) # Always uses Release mode to build BDS plugin for ABI Compatibility
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/x64/)
set(TARGET_DIR ${CMAKE_SOURCE_DIR}/x64/Release/)
file(GLOB_RECURSE SRC_FILES
${PROJECT_SOURCE_DIR}/Lib/third-party/nbt-cpp/*.cpp
${PROJECT_SOURCE_DIR}/Header/*.cpp
${PROJECT_SOURCE_DIR}/Header/*.hpp
${PROJECT_SOURCE_DIR}/Header/*.h
${PROJECT_SOURCE_DIR}/Kernel/*.cpp
${PROJECT_SOURCE_DIR}/Kernel/*.hpp
${PROJECT_SOURCE_DIR}/Kernel/*.h
${PROJECT_SOURCE_DIR}/Main/*.cpp
${PROJECT_SOURCE_DIR}/Main/*.hpp
${PROJECT_SOURCE_DIR}/Main/*.h
${PROJECT_SOURCE_DIR}/Resource/*.rc
${PROJECT_SOURCE_DIR}/Resource/*.h
file(
GLOB_RECURSE SRC_FILES
${PROJECT_SOURCE_DIR}/third-party/include/*.h
${PROJECT_SOURCE_DIR}/third-party/include/*.hpp
${PROJECT_SOURCE_DIR}/include/*.h
${PROJECT_SOURCE_DIR}/include/*.hpp
${PROJECT_SOURCE_DIR}/src/*.cpp
${PROJECT_SOURCE_DIR}/src/*.hpp
${PROJECT_SOURCE_DIR}/src/*.h
${PROJECT_SOURCE_DIR}/src/*.rc
)
add_definitions(
-DUNICODE -DNDEBUG -DLITELOADER_EXPORTS -DWIN32_LEAN_AND_MEAN
-DCPPHTTPLIB_OPENSSL_SUPPORT -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS
-D_USRDLL -D_AMD64_ -DNOMINMAX
# third-party source files
file(GLOB_RECURSE THIRD_PARTY_SRC_FILES ${PROJECT_SOURCE_DIR}/third-party/src/*)
add_library(LiteLoader SHARED ${SRC_FILES} ${THIRD_PARTY_SRC_FILES})
# Replace Compile Flag /EHsc to /EHa
string(REPLACE "/EHsc" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
target_compile_options(
LiteLoader
PRIVATE /permissive- /MD /MP /analyze:external- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /FC /nologo /Ot /diagnostics:column /utf-8
)
add_compile_options(
/permissive /MP /analyze:external- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Zc:inline /fp:precise
/external:W1 /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /EHa /nologo /Ot /diagnostics:column
/utf-8
target_compile_definitions(
LiteLoader
PRIVATE -DUNICODE -DNDEBUG -DLITELOADER_EXPORTS -DWIN32_LEAN_AND_MEAN -DCPPHTTPLIB_OPENSSL_SUPPORT -D_CRT_SECURE_NO_WARNINGS -D_WINDOWS -D_USRDLL -D_AMD64_ -DNOMINMAX
)
add_link_options(
/MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG:FULL /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:CONSOLE
/MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
/DELAYLOAD:bedrock_server.dll # use delayload to import BDS APIs manually(bedrock_server.dll does not need to exist)
# use delayload to import BDS APIs manually(bedrock_server.dll does not need to exist)
target_link_options(
LiteLoader
PRIVATE /MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG:FULL /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:CONSOLE /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 /DELAYLOAD:bedrock_server.dll
)
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/Header)
include_directories(${PROJECT_SOURCE_DIR}/Header/third-party)
include_directories(${CMAKE_SOURCE_DIR})
link_directories(${PROJECT_SOURCE_DIR})
link_directories(${CMAKE_SOURCE_DIR}/x64/Release)
add_library(LiteLoader SHARED ${SRC_FILES})
target_link_libraries(LiteLoader LLPreLoader
"${PROJECT_SOURCE_DIR}/Lib/third-party/leveldb/leveldb.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/openssl/libcrypto.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/openssl/libssl.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/SQLiteCpp/SQLiteCpp.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/SQLiteCpp/sqlite3.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/mysql/mysqlclient.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dyncall_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dyncallback_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dyncall/dynload_s.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/Lib/third-party/dbghelp/dbghelp.lib"
target_link_libraries(
LiteLoader
"${PROJECT_SOURCE_DIR}/third-party/lib/leveldb/leveldb.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/openssl/libcrypto.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/openssl/libssl.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/SQLiteCpp/SQLiteCpp.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/SQLiteCpp/sqlite3.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/mysql/mysqlclient.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/compact_enc_det/ced.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dyncall_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dyncallback_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dyncall/dynload_s.lib"
"${PROJECT_SOURCE_DIR}/third-party/lib/dbghelp/dbghelp.lib"
# Please make sure that the BDS APIs ImportLibrary is at the bottom of the list to ensure proper linking.
"${PROJECT_SOURCE_DIR}/Lib/bedrock_server_api.lib"
"${PROJECT_SOURCE_DIR}/Lib/bedrock_server_var.lib"
LLPreLoader
)
target_include_directories(
LiteLoader SYSTEM
PRIVATE ${PROJECT_SOURCE_DIR}/third-party/include
)
target_include_directories(
LiteLoader
PRIVATE ${PROJECT_SOURCE_DIR}/include/
PRIVATE ${CMAKE_SOURCE_DIR}
)
add_custom_command(
TARGET LiteLoader PRE_BUILD
COMMAND ${CMAKE_SOURCE_DIR}/scripts/PrepareLibraries.cmd ${CMAKE_SOURCE_DIR}
)
# Copy the built DLL and PDB to the output directory
add_custom_command(
TARGET LiteLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/output/
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PDB_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/pdb/
COMMENT "Copying LiteLoader DLL and PDB to output directory"
VERBATIM
)
# Copy the built lib to the SDK directory
add_custom_command(
TARGET LiteLoader POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:LiteLoader> ${CMAKE_BINARY_DIR}/sdk/lib/
COMMENT "Copying LiteLoader Lib to SDK directory"
VERBATIM
)

View File

@ -1,5 +0,0 @@
#pragma once
#include "../Global.h"
LIAPI uint64_t NewScoreId();

View File

@ -1,29 +0,0 @@
// This Header is auto generated by BDSLiteLoader Toolchain
#pragma once
#define AUTO_GENERATED
#include "../Global.h"
#define BEFORE_EXTRA
#undef BEFORE_EXTRA
class DataItem {
#define AFTER_EXTRA
#undef AFTER_EXTRA
#ifndef DISABLE_CONSTRUCTOR_PREVENTION_DATAITEM
public:
class DataItem& operator=(class DataItem const &) = delete;
DataItem(class DataItem const &) = delete;
DataItem() = delete;
#endif
public:
/*0*/ virtual ~DataItem();
/*1*/ virtual bool isDataEqual(class DataItem const &) const;
/*2*/ virtual std::unique_ptr<class DataItem> clone() const = 0;
#ifdef ENABLE_VIRTUAL_FAKESYMBOL_DATAITEM
#endif
};

View File

@ -1,31 +0,0 @@
// This Header is auto generated by BDSLiteLoader Toolchain
#pragma once
#define AUTO_GENERATED
#include "../Global.h"
#define BEFORE_EXTRA
#undef BEFORE_EXTRA
class OwnerStorageEntity {
#define AFTER_EXTRA
#undef AFTER_EXTRA
#ifndef DISABLE_CONSTRUCTOR_PREVENTION_OWNERSTORAGEENTITY
public:
class OwnerStorageEntity& operator=(class OwnerStorageEntity const &) = delete;
OwnerStorageEntity(class OwnerStorageEntity const &) = delete;
OwnerStorageEntity() = delete;
#endif
public:
#ifdef ENABLE_VIRTUAL_FAKESYMBOL_OWNERSTORAGEENTITY
#endif
//protected:
MCAPI void _reset();
protected:
};

View File

@ -1,38 +0,0 @@
// This Header is auto generated by BDSLiteLoader Toolchain
#pragma once
#define AUTO_GENERATED
#include "../Global.h"
#define BEFORE_EXTRA
#undef BEFORE_EXTRA
class SynchedActorData {
#define AFTER_EXTRA
#undef AFTER_EXTRA
#ifndef DISABLE_CONSTRUCTOR_PREVENTION_SYNCHEDACTORDATA
public:
class SynchedActorData& operator=(class SynchedActorData const &) = delete;
SynchedActorData(class SynchedActorData const &) = delete;
SynchedActorData() = delete;
#endif
public:
#ifdef ENABLE_VIRTUAL_FAKESYMBOL_SYNCHEDACTORDATA
#endif
MCAPI class CompoundTag const & getCompoundTag(unsigned short) const;
MCAPI float getFloat(unsigned short) const;
MCAPI signed char getInt8(unsigned short) const;
MCAPI std::string const & getString(unsigned short) const;
MCAPI std::vector<std::unique_ptr<class DataItem>> packAll() const;
MCAPI std::vector<std::unique_ptr<class DataItem>> packDirty();
MCAPI ~SynchedActorData();
//private:
MCAPI void _resizeToContain(unsigned short);
private:
};

View File

@ -1,85 +0,0 @@
#ifndef ENTT_CONFIG_CONFIG_H
#define ENTT_CONFIG_CONFIG_H
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
# define ENTT_NOEXCEPT noexcept
# define ENTT_THROW throw
# define ENTT_TRY try
# define ENTT_CATCH catch(...)
#else
# define ENTT_NOEXCEPT
# define ENTT_THROW
# define ENTT_TRY if(true)
# define ENTT_CATCH if(false)
#endif
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
# include <new>
# define ENTT_LAUNDER(expr) std::launder(expr)
#else
# define ENTT_LAUNDER(expr) expr
#endif
#ifndef ENTT_USE_ATOMIC
# define ENTT_MAYBE_ATOMIC(Type) Type
#else
# include <atomic>
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
#endif
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
#endif
#ifdef ENTT_SPARSE_PAGE
static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE & (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two");
#else
# define ENTT_SPARSE_PAGE 4096
#endif
#ifdef ENTT_PACKED_PAGE
static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE & (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two");
#else
# define ENTT_PACKED_PAGE 1024
#endif
#ifdef ENTT_DISABLE_ASSERT
# undef ENTT_ASSERT
# define ENTT_ASSERT(...) (void(0))
#elif !defined ENTT_ASSERT
# include <cassert>
# define ENTT_ASSERT(condition, ...) assert(condition)
#endif
#ifdef ENTT_NO_ETO
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::false_type
#else
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::true_type
#endif
#ifndef ENTT_STANDARD_CPP
# if defined __clang__ || defined __GNUC__
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
# define ENTT_PRETTY_FUNCTION_PREFIX '='
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
# elif defined _MSC_VER
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
# endif
#endif
#endif

View File

@ -1,10 +0,0 @@
#ifndef ENTT_CONFIG_VERSION_H
#define ENTT_CONFIG_VERSION_H
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 8
#define ENTT_VERSION_PATCH 1
#endif

View File

@ -1,456 +0,0 @@
#ifndef ENTT_CORE_ANY_HPP
#define ENTT_CORE_ANY_HPP
#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/utility.hpp"
#include "fwd.hpp"
#include "type_info.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief A SBO friendly, type-safe container for single values of any type.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
*/
template<std::size_t Len, std::size_t Align>
class basic_any {
enum class operation: std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE };
enum class policy: std::uint8_t { OWNER, REF, CREF };
using storage_type = std::aligned_storage_t<Len + !Len, Align>;
using vtable_type = const void *(const operation, const basic_any &, void *);
template<typename Type>
static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
template<typename Type>
[[nodiscard]] static constexpr policy type_to_policy() {
if constexpr(std::is_lvalue_reference_v<Type>) {
if constexpr(std::is_const_v<std::remove_reference_t<Type>>) {
return policy::CREF;
} else {
return policy::REF;
}
} else {
return policy::OWNER;
}
}
template<typename Type>
[[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
return lhs == rhs;
}
}
template<typename Type>
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] void *to) {
static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
if constexpr(!std::is_void_v<Type>) {
const Type *instance = (in_situ<Type> && from.mode == policy::OWNER)
? ENTT_LAUNDER(reinterpret_cast<const Type *>(&from.storage))
: static_cast<const Type *>(from.instance);
switch(op) {
case operation::COPY:
if constexpr(std::is_copy_constructible_v<Type>) {
static_cast<basic_any *>(to)->emplace<Type>(*instance);
}
break;
case operation::MOVE:
if constexpr(in_situ<Type>) {
if(from.mode == policy::OWNER) {
return new (&static_cast<basic_any *>(to)->storage) Type{std::move(*const_cast<Type *>(instance))};
}
}
return (static_cast<basic_any *>(to)->instance = std::exchange(const_cast<basic_any &>(from).instance, nullptr));
case operation::DTOR:
if(from.mode == policy::OWNER) {
if constexpr(in_situ<Type>) {
instance->~Type();
} else if constexpr(std::is_array_v<Type>) {
delete[] instance;
} else {
delete instance;
}
}
break;
case operation::COMP:
return compare<Type>(instance, (*static_cast<const basic_any **>(to))->data()) ? to : nullptr;
case operation::ADDR:
if(from.mode == policy::CREF) {
return nullptr;
}
[[fallthrough]];
case operation::CADDR:
return instance;
case operation::TYPE:
*static_cast<type_info *>(to) = type_id<Type>();
break;
}
}
return nullptr;
}
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&... args) {
if constexpr(!std::is_void_v<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<Type>) {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
new (&storage) Type{std::forward<Args>(args)...};
} else {
new (&storage) Type(std::forward<Args>(args)...);
}
} else {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
instance = new Type{std::forward<Args>(args)...};
} else {
instance = new Type(std::forward<Args>(args)...);
}
}
}
}
basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
: instance{other.data()},
vtable{other.vtable},
mode{pol}
{}
public:
/*! @brief Size of the internal storage. */
static constexpr auto length = Len;
/*! @brief Alignment requirement. */
static constexpr auto alignment = Align;
/*! @brief Default constructor. */
basic_any() ENTT_NOEXCEPT
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{}
/**
* @brief Constructs a wrapper by directly initializing the new object.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit basic_any(std::in_place_type_t<Type>, Args &&... args)
: instance{},
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
mode{type_to_policy<Type>()}
{
initialize<Type>(std::forward<Args>(args)...);
}
/**
* @brief Constructs a wrapper that holds an unmanaged object.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type>
basic_any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
: basic_any{}
{
// invokes deprecated assignment operator (and avoids issues with vs2017)
*this = value;
}
/**
* @brief Constructs a wrapper from a given value.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
basic_any(Type &&value)
: instance{},
vtable{&basic_vtable<std::decay_t<Type>>},
mode{policy::OWNER}
{
initialize<std::decay_t<Type>>(std::forward<Type>(value));
}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
basic_any(const basic_any &other)
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{
other.vtable(operation::COPY, other, this);
}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_any(basic_any &&other) ENTT_NOEXCEPT
: instance{},
vtable{other.vtable},
mode{other.mode}
{
vtable(operation::MOVE, other, this);
}
/*! @brief Frees the internal storage, whatever it means. */
~basic_any() {
vtable(operation::DTOR, *this, nullptr);
}
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This any object.
*/
basic_any & operator=(const basic_any &other) {
reset();
other.vtable(operation::COPY, other, this);
return *this;
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This any object.
*/
basic_any & operator=(basic_any &&other) ENTT_NOEXCEPT {
std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr);
other.vtable(operation::MOVE, other, this);
mode = other.mode;
return *this;
}
/**
* @brief Value assignment operator.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
* @return This any object.
*/
template<typename Type>
[[deprecated("Use std::in_place_type<T &>, entt::make_any<T &>, emplace<Type &> or forward_as_any instead")]]
basic_any & operator=(std::reference_wrapper<Type> value) ENTT_NOEXCEPT {
emplace<Type &>(value.get());
return *this;
}
/**
* @brief Value assignment operator.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
* @return This any object.
*/
template<typename Type>
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &>
operator=(Type &&value) {
emplace<std::decay_t<Type>>(std::forward<Type>(value));
return *this;
}
/**
* @brief Returns the type of the contained object.
* @return The type of the contained object, if any.
*/
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
type_info info{};
vtable(operation::TYPE, *this, &info);
return info;
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
return vtable(operation::CADDR, *this, nullptr);
}
/*! @copydoc data */
[[nodiscard]] void * data() ENTT_NOEXCEPT {
return const_cast<void *>(vtable(operation::ADDR, *this, nullptr));
}
/**
* @brief Replaces the contained object by creating a new instance directly.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
void emplace(Args &&... args) {
std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>)(operation::DTOR, *this, nullptr);
mode = type_to_policy<Type>();
initialize<Type>(std::forward<Args>(args)...);
}
/*! @brief Destroys contained object */
void reset() {
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, *this, nullptr);
mode = policy::OWNER;
}
/**
* @brief Returns false if a wrapper is empty, true otherwise.
* @return False if the wrapper is empty, true otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return !(vtable(operation::CADDR, *this, nullptr) == nullptr);
}
/**
* @brief Checks if two wrappers differ in their content.
* @param other Wrapper with which to compare.
* @return False if the two objects differ in their content, true otherwise.
*/
bool operator==(const basic_any &other) const ENTT_NOEXCEPT {
const basic_any *trampoline = &other;
return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data());
}
/**
* @brief Aliasing constructor.
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT {
return basic_any{*this, (mode == policy::CREF ? policy::CREF : policy::REF)};
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT {
return basic_any{*this, policy::CREF};
}
/**
* @brief Returns true if a wrapper owns its object, false otherwise.
* @return True if the wrapper owns its object, false otherwise.
*/
[[nodiscard]] bool owner() const ENTT_NOEXCEPT {
return (mode == policy::OWNER);
}
private:
union { const void *instance; storage_type storage; };
vtable_type *vtable;
policy mode;
};
/**
* @brief Checks if two wrappers differ in their content.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param lhs A wrapper, either empty or not.
* @param rhs A wrapper, either empty or not.
* @return True if the two wrappers differ in their content, false otherwise.
*/
template<std::size_t Len, std::size_t Align>
[[nodiscard]] inline bool operator!=(const basic_any<Len, Align> &lhs, const basic_any<Len, Align> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param data Target any object.
* @return The element converted to the requested type.
*/
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(std::move(*instance));
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
const Type * any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
return (data->type() == type_id<Type>() ? static_cast<const Type *>(data->data()) : nullptr);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type * any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
// last attempt to make wrappers for const references return their values
return (data->type() == type_id<Type>() ? static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data()) : nullptr);
}
/**
* @brief Constructs a wrapper from a given type, passing it all arguments.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
* @return A properly initialized wrapper for an object of the given type.
*/
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
basic_any<Len, Align> make_any(Args &&... args) {
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
}
/**
* @brief Forwards its argument and avoids copies for lvalue references.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Type Type of argument to use to construct the new instance.
* @param value Parameter to use to construct the instance.
* @return A properly initialized and not necessarily owning wrapper.
*/
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
}
}
#endif

View File

@ -1,33 +0,0 @@
#ifndef ENTT_CORE_ATTRIBUTE_H
#define ENTT_CORE_ATTRIBUTE_H
#ifndef ENTT_EXPORT
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
# define ENTT_EXPORT __declspec(dllexport)
# define ENTT_IMPORT __declspec(dllimport)
# define ENTT_HIDDEN
# elif defined __GNUC__ && __GNUC__ >= 4
# define ENTT_EXPORT __attribute__((visibility("default")))
# define ENTT_IMPORT __attribute__((visibility("default")))
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
# else /* Unsupported compiler */
# define ENTT_EXPORT
# define ENTT_IMPORT
# define ENTT_HIDDEN
# endif
#endif
#ifndef ENTT_API
# if defined ENTT_API_EXPORT
# define ENTT_API ENTT_EXPORT
# elif defined ENTT_API_IMPORT
# define ENTT_API ENTT_IMPORT
# else /* No API */
# define ENTT_API
# endif
#endif
#endif

View File

@ -1,269 +0,0 @@
#ifndef ENTT_CORE_HASHED_STRING_HPP
#define ENTT_CORE_HASHED_STRING_HPP
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename>
struct fnv1a_traits;
template<>
struct fnv1a_traits<std::uint32_t> {
using type = std::uint32_t;
static constexpr std::uint32_t offset = 2166136261;
static constexpr std::uint32_t prime = 16777619;
};
template<>
struct fnv1a_traits<std::uint64_t> {
using type = std::uint64_t;
static constexpr std::uint64_t offset = 14695981039346656037ull;
static constexpr std::uint64_t prime = 1099511628211ull;
};
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Zero overhead unique identifier.
*
* A hashed string is a compile-time tool that allows users to use
* human-readable identifers in the codebase while using their numeric
* counterparts at runtime.<br/>
* Because of that, a hashed string can also be used in constant expressions if
* required.
*
* @tparam Char Character type.
*/
template<typename Char>
class basic_hashed_string {
using traits_type = internal::fnv1a_traits<id_type>;
struct const_wrapper {
// non-explicit constructor on purpose
constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
const Char *str;
};
// FowlerNollVo hash function v. 1a - the good
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
auto value = traits_type::offset;
while(*curr != 0) {
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
}
return value;
}
public:
/*! @brief Character type. */
using value_type = Char;
/*! @brief Unsigned integer type. */
using hash_type = id_type;
/**
* @brief Returns directly the numeric representation of a string view.
* @param str Human-readable identifer.
* @param size Length of the string to hash.
* @return The numeric representation of the string.
*/
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
id_type partial{traits_type::offset};
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
return partial;
}
/**
* @brief Returns directly the numeric representation of a string.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* const auto value = basic_hashed_string<char>::to_value("my.png");
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @return The numeric representation of the string.
*/
template<std::size_t N>
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
return helper(str);
}
/**
* @brief Returns directly the numeric representation of a string.
* @param wrapper Helps achieving the purpose by relying on overloading.
* @return The numeric representation of the string.
*/
[[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(wrapper.str);
}
/*! @brief Constructs an empty hashed string. */
constexpr basic_hashed_string() ENTT_NOEXCEPT
: str{nullptr}, hash{}
{}
/**
* @brief Constructs a hashed string from an array of const characters.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* basic_hashed_string<char> hs{"my.png"};
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param curr Human-readable identifer.
*/
template<std::size_t N>
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
: str{curr}, hash{helper(curr)}
{}
/**
* @brief Explicit constructor on purpose to avoid constructing a hashed
* string directly from a `const value_type *`.
* @param wrapper Helps achieving the purpose by relying on overloading.
*/
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
: str{wrapper.str}, hash{helper(wrapper.str)}
{}
/**
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
*/
[[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT {
return str;
}
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
[[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT {
return hash;
}
/*! @copydoc data */
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
/**
* @brief Compares two hashed strings.
* @param other Hashed string with which to compare.
* @return True if the two hashed strings are identical, false otherwise.
*/
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
return hash == other.hash;
}
private:
const value_type *str;
hash_type hash;
};
/**
* @brief Deduction guide.
*
* It allows to deduce the character type of the hashed string directly from a
* human-readable identifer provided to the constructor.
*
* @tparam Char Character type.
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
*/
template<typename Char, std::size_t N>
basic_hashed_string(const Char (&str)[N])
-> basic_hashed_string<Char>;
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the two hashed strings are identical, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/*! @brief Aliases for common character types. */
using hashed_string = basic_hashed_string<char>;
/*! @brief Aliases for common character types. */
using hashed_wstring = basic_hashed_string<wchar_t>;
inline namespace literals {
/**
* @brief User defined literal for hashed strings.
* @param str The literal without its suffix.
* @return A properly initialized hashed string.
*/
[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_string{str};
}
/**
* @brief User defined literal for hashed wstrings.
* @param str The literal without its suffix.
* @return A properly initialized hashed wstring.
*/
[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_wstring{str};
}
}
}
#endif

View File

@ -1,64 +0,0 @@
#ifndef ENTT_CORE_IDENT_HPP
#define ENTT_CORE_IDENT_HPP
#include <cstddef>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Types identifiers.
*
* Variable template used to generate identifiers at compile-time for the given
* types. Use the `get` member function to know what's the identifier associated
* to the specific type.
*
* @note
* Identifiers are constant expression and can be used in any context where such
* an expression is required. As an example:
* @code{.cpp}
* using id = entt::identifier<a_type, another_type>;
*
* switch(a_type_identifier) {
* case id::type<a_type>:
* // ...
* break;
* case id::type<another_type>:
* // ...
* break;
* default:
* // ...
* }
* @endcode
*
* @tparam Types List of types for which to generate identifiers.
*/
template<typename... Types>
class identifier {
template<typename Type, std::size_t... Index>
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) {
static_assert(std::disjunction_v<std::is_same<Type, Types>...>, "Invalid type");
return (0 + ... + (std::is_same_v<Type, type_list_element_t<Index, type_list<std::decay_t<Types>...>>> ? id_type{Index} : id_type{}));
}
public:
/*! @brief Unsigned integer type. */
using identifier_type = id_type;
/*! @brief Statically generated unique identifier for the given type. */
template<typename Type>
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
};
}
#endif

View File

@ -1,260 +0,0 @@
#ifndef ENTT_CORE_TYPE_INFO_HPP
#define ENTT_CORE_TYPE_INFO_HPP
#include <string_view>
#include <type_traits>
#include "../config/config.h"
#include "../core/attribute.h"
#include "hashed_string.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct ENTT_API type_seq final {
[[nodiscard]] static id_type next() ENTT_NOEXCEPT {
static ENTT_MAYBE_ATOMIC(id_type) value{};
return value++;
}
};
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT {
#if defined ENTT_PRETTY_FUNCTION
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1);
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
return value;
#else
return std::string_view{""};
#endif
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT {
constexpr auto value = stripped_type_name<Type>();
return value;
}
template<typename Type>
[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT {
static const auto value = stripped_type_name<Type>();
return value;
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT {
constexpr auto stripped = stripped_type_name<Type>();
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
return value;
}
template<typename Type>
[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT {
static const auto value = [](const auto stripped) {
return hashed_string::value(stripped.data(), stripped.size());
}(stripped_type_name<Type>());
return value;
}
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Type sequential identifier.
* @tparam Type Type for which to generate a sequential identifier.
*/
template<typename Type, typename = void>
struct ENTT_API type_seq final {
/**
* @brief Returns the sequential identifier of a given type.
* @return The sequential identifier of a given type.
*/
[[nodiscard]] static id_type value() ENTT_NOEXCEPT {
static const id_type value = internal::type_seq::next();
return value;
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
};
/**
* @brief Type hash.
* @tparam Type Type for which to generate a hash value.
*/
template<typename Type, typename = void>
struct type_hash final {
/**
* @brief Returns the numeric representation of a given type.
* @return The numeric representation of the given type.
*/
#if defined ENTT_PRETTY_FUNCTION
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return internal::type_hash<Type>(0);
#else
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return type_seq<Type>::value();
#endif
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
};
/**
* @brief Type name.
* @tparam Type Type for which to generate a name.
*/
template<typename Type, typename = void>
struct type_name final {
/**
* @brief Returns the name of a given type.
* @return The name of the given type.
*/
[[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT {
return internal::type_name<Type>(0);
}
/*! @copydoc value */
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); }
};
/*! @brief Implementation specific information about a type. */
class type_info final {
template<typename>
friend type_info type_id() ENTT_NOEXCEPT;
type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT
: seq_value{seq_v},
hash_value{hash_v},
name_value{name_v}
{}
public:
/*! @brief Default constructor. */
type_info() ENTT_NOEXCEPT
: type_info({}, {}, {})
{}
/*! @brief Default copy constructor. */
type_info(const type_info &) ENTT_NOEXCEPT = default;
/*! @brief Default move constructor. */
type_info(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Default copy assignment operator.
* @return This type info object.
*/
type_info & operator=(const type_info &) ENTT_NOEXCEPT = default;
/**
* @brief Default move assignment operator.
* @return This type info object.
*/
type_info & operator=(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Checks if a type info object is properly initialized.
* @return True if the object is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return name_value.data() != nullptr;
}
/**
* @brief Type sequential identifier.
* @return Type sequential identifier.
*/
[[nodiscard]] id_type seq() const ENTT_NOEXCEPT {
return seq_value;
}
/**
* @brief Type hash.
* @return Type hash.
*/
[[nodiscard]] id_type hash() const ENTT_NOEXCEPT {
return hash_value;
}
/**
* @brief Type name.
* @return Type name.
*/
[[nodiscard]] std::string_view name() const ENTT_NOEXCEPT {
return name_value;
}
/**
* @brief Compares the contents of two type info objects.
* @param other Object with which to compare.
* @return False if the two contents differ, true otherwise.
*/
[[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT {
return hash_value == other.hash_value;
}
private:
id_type seq_value;
id_type hash_value;
std::string_view name_value;
};
/**
* @brief Compares the contents of two type info objects.
* @param lhs A type info object.
* @param rhs A type info object.
* @return True if the two contents differ, false otherwise.
*/
[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Returns the type info object for a given type.
* @tparam Type Type for which to generate a type info object.
* @return The type info object for the given type.
*/
template<typename Type>
[[nodiscard]] type_info type_id() ENTT_NOEXCEPT {
return type_info{
type_seq<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()
};
}
}
#endif

View File

@ -1,34 +0,0 @@
#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP
#include <type_traits>
#include "../config/config.h"
namespace entt {
/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
/*! @brief Pointer stability, default is `std::false_type`. */
using in_place_delete = std::false_type;
/*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
};
/**
* @brief Common way to access various properties of components.
* @tparam Type Type of component.
*/
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};
}
#endif

View File

@ -1,147 +0,0 @@
#ifndef ENTT_ENTITY_FWD_HPP
#define ENTT_ENTITY_FWD_HPP
#include <memory>
#include "../core/fwd.hpp"
namespace entt {
template<typename Entity, typename = std::allocator<Entity>>
class basic_sparse_set;
template<typename, typename Type, typename = std::allocator<Type>>
struct basic_storage;
template<typename>
class basic_registry;
template<typename...>
struct basic_view;
template<typename>
class basic_runtime_view;
template<typename...>
class basic_group;
template<typename>
class basic_observer;
template<typename>
class basic_organizer;
template<typename, typename...>
struct basic_handle;
template<typename>
class basic_snapshot;
template<typename>
class basic_snapshot_loader;
template<typename>
class basic_continuous_loader;
/*! @brief Default entity identifier. */
enum class entity: id_type {};
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using storage = basic_storage<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<entity>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<entity>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<entity>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<entity>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using handle_view = basic_handle<entity, Args...>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using const_handle_view = basic_handle<const entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<entity>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<entity>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using view = basic_view<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using group = basic_group<entity, Args...>;
}
#endif

View File

@ -1,969 +0,0 @@
#ifndef ENTT_ENTITY_GROUP_HPP
#define ENTT_ENTITY_GROUP_HPP
#include <tuple>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "sparse_set.hpp"
#include "storage.hpp"
#include "utility.hpp"
namespace entt {
/**
* @brief Group.
*
* Primary template isn't defined on purpose. All the specializations give a
* compile-time error, but for a few reasonable cases.
*/
template<typename...>
class basic_group;
/**
* @brief Non-owning group.
*
* A non-owning group returns all entities and only the entities that have at
* least the given components. Moreover, it's guaranteed that the entity list
* is tightly packed in memory for fast iterations.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all other cases, modifying the pools iterated by the group in any way
* invalidates all the iterators and using them results in undefined behavior.
*
* @note
* Groups share references to the underlying data structures of the registry
* that generated them. Therefore any change to the entities and to the
* components made by means of the registry are immediately reflected by all the
* groups.<br/>
* Moreover, sorting a non-owning group affects all the instances of the same
* group (it means that users don't have to call `sort` on each instance to sort
* all of them because they _share_ entities and components).
*
* @warning
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Type of components observed by the group.
*/
template<typename Entity, typename... Exclude, typename... Get>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;
using basic_common_type = basic_sparse_set<Entity>;
template<typename Component>
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
class iterable final {
template<typename It>
struct iterable_iterator final {
using difference_type = std::ptrdiff_t;
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
template<typename... Args>
iterable_iterator(It from, const std::tuple<storage_type<Get> *...> &args) ENTT_NOEXCEPT
: it{from},
pools{args}
{}
iterable_iterator & operator++() ENTT_NOEXCEPT {
return ++it, *this;
}
iterable_iterator operator++(int) ENTT_NOEXCEPT {
iterable_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
const auto entt = *it;
return std::tuple_cat(std::make_tuple(entt), get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
}
[[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
std::tuple<storage_type<Get> *...> pools;
};
public:
using iterator = iterable_iterator<typename basic_common_type::iterator>;
using reverse_iterator = iterable_iterator<typename basic_common_type::reverse_iterator>;
iterable(basic_common_type * const ref, const std::tuple<storage_type<Get> *...> &cpools)
: handler{ref},
pools{cpools}
{}
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return handler ? iterator{handler->begin(), pools} : iterator{{}, pools};
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return handler ? iterator{handler->end(), pools} : iterator{{}, pools};
}
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return handler ? reverse_iterator{handler->rbegin(), pools} : reverse_iterator{{}, pools};
}
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return handler ? reverse_iterator{handler->rend(), pools} : reverse_iterator{{}, pools};
}
private:
basic_common_type * const handler;
const std::tuple<storage_type<Get> *...> pools;
};
basic_group(basic_common_type &ref, storage_type<Get> &... gpool) ENTT_NOEXCEPT
: handler{&ref},
pools{&gpool...}
{}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator = typename basic_common_type::iterator;
/*! @brief Reversed iterator type. */
using reverse_iterator = typename basic_common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable_group = iterable;
/*! @brief Default constructor to use to create empty, invalid groups. */
basic_group() ENTT_NOEXCEPT
: handler{}
{}
/**
* @brief Returns the number of entities that have the given components.
* @return Number of entities that have the given components.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return *this ? handler->size() : size_type{};
}
/**
* @brief Returns the number of elements that a group has currently
* allocated space for.
* @return Capacity of the group.
*/
[[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
return *this ? handler->capacity() : size_type{};
}
/*! @brief Requests the removal of unused capacity. */
void shrink_to_fit() {
if(*this) {
handler->shrink_to_fit();
}
}
/**
* @brief Checks whether a group is empty.
* @return True if the group is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return !*this || handler->empty();
}
/**
* @brief Direct access to the list of entities.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] auto data() const ENTT_NOEXCEPT {
return *this ? handler->data() : nullptr;
}
/**
* @brief Returns an iterator to the first entity of the group.
*
* The returned iterator points to the first entity of the group. If the
* group is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the group.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return *this ? handler->begin() : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the group.
*
* The returned iterator points to the entity following the last entity of
* the group. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* group.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return *this ? handler->end() : iterator{};
}
/**
* @brief Returns an iterator to the first entity of the reversed group.
*
* The returned iterator points to the first entity of the reversed group.
* If the group is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first entity of the reversed group.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return *this ? handler->rbegin() : reverse_iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* group.
*
* The returned iterator points to the entity following the last entity of
* the reversed group. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* reversed group.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return *this ? handler->rend() : reverse_iterator{};
}
/**
* @brief Returns the first entity of the group, if any.
* @return The first entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type front() const {
const auto it = begin();
return it != end() ? *it : null;
}
/**
* @brief Returns the last entity of the group, if any.
* @return The last entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type back() const {
const auto it = rbegin();
return it != rend() ? *it : null;
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const {
const auto it = *this ? handler->find(entt) : iterator{};
return it != end() && *it == entt ? it : end();
}
/**
* @brief Returns the identifier that occupies the given position.
* @param pos Position of the element to return.
* @return The identifier that occupies the given position.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const {
return begin()[pos];
}
/**
* @brief Checks if a group is properly initialized.
* @return True if the group is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return handler != nullptr;
}
/**
* @brief Checks if a group contains an entity.
* @param entt A valid entity identifier.
* @return True if the group contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return *this && handler->contains(entt);
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `registry::get` during iterations. It has
* far better performance than its counterpart.
*
* @warning
* Attempting to use an invalid component type results in a compilation
* error. Attempting to use an entity that doesn't belong to the group
* results in undefined behavior.
*
* @tparam Component Types of components to get.
* @param entt A valid entity identifier.
* @return The components assigned to the entity.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
ENTT_ASSERT(contains(entt), "Group does not contain entity");
if constexpr(sizeof...(Component) == 0) {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
} else if constexpr(sizeof...(Component) == 1) {
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
} else {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
}
}
/**
* @brief Iterates entities and components and applies the given function
* object to them.
*
* The function object is invoked for each entity. It is provided with the
* entity itself and a set of references to non-empty components. The
* _constness_ of the components is as requested.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entity_type, Type &...);
* void(Type &...);
* @endcode
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(const auto entt: *this) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
} else {
std::apply(func, get(entt));
}
}
}
/**
* @brief Returns an iterable object to use to _visit_ the group.
*
* The iterable object returns tuples that contain the current entity and a
* set of references to its non-empty components. The _constness_ of the
* components is as requested.
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
return iterable_group{handler, pools};
}
/**
* @brief Sort a group according to the given comparison function.
*
* Sort the group so that iterating it with a couple of iterators returns
* entities and components in the expected order. See `begin` and `end` for
* more details.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Component &...>, std::tuple<Component &...>);
* bool(const Component &..., const Component &...);
* bool(const Entity, const Entity);
* @endcode
*
* Where `Component` are such that they are iterated by the group.<br/>
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function oject must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Component Optional types of components to compare.
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
if(*this) {
if constexpr(sizeof...(Component) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
} else if constexpr(sizeof...(Component) == 1) {
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
}, std::move(algo), std::forward<Args>(args)...);
} else {
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
}, std::move(algo), std::forward<Args>(args)...);
}
}
}
/**
* @brief Sort the shared pool of entities according to the given component.
*
* Non-owning groups of the same type share with the registry a pool of
* entities with its own order that doesn't depend on the order of any pool
* of components. Users can order the underlying data structure so that it
* respects the order of the pool of the given component.
*
* @note
* The shared pool of entities and thus its order is affected by the changes
* to each and every pool that it tracks. Therefore changes to those pools
* can quickly ruin the order imposed to the pool of entities shared between
* the non-owning groups.
*
* @tparam Component Type of component to use to impose the order.
*/
template<typename Component>
void sort() const {
if(*this) {
handler->respect(*std::get<storage_type<Component> *>(pools));
}
}
private:
basic_common_type * const handler;
const std::tuple<storage_type<Get> *...> pools;
};
/**
* @brief Owning group.
*
* Owning groups return all entities and only the entities that have at least
* the given components. Moreover:
*
* * It's guaranteed that the entity list is tightly packed in memory for fast
* iterations.
* * It's guaranteed that the lists of owned components are tightly packed in
* memory for even faster iterations and to allow direct access.
* * They stay true to the order of the owned components and all instances have
* the same order in memory.
*
* The more types of components are owned by a group, the faster it is to
* iterate them.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all other cases, modifying the pools iterated by the group in any way
* invalidates all the iterators and using them results in undefined behavior.
*
* @note
* Groups share references to the underlying data structures of the registry
* that generated them. Therefore any change to the entities and to the
* components made by means of the registry are immediately reflected by all the
* groups.
* Moreover, sorting an owning group affects all the instance of the same group
* (it means that users don't have to call `sort` on each instance to sort all
* of them because they share the underlying data structure).
*
* @warning
* Lifetime of a group must not overcome that of the registry that generated it.
* In any other case, attempting to use a group results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Types of components owned by the group.
*/
template<typename Entity, typename... Exclude, typename... Get, typename... Owned>
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final {
/*! @brief A registry is allowed to create groups. */
friend class basic_registry<Entity>;
using basic_common_type = basic_sparse_set<Entity>;
template<typename Component>
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
class iterable final {
template<typename, typename>
struct iterable_iterator;
template<typename It, typename... OIt>
struct iterable_iterator<It, type_list<OIt...>> final {
using difference_type = std::ptrdiff_t;
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
template<typename... Other>
iterable_iterator(It from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
: it{from},
owned{std::get<OIt>(other)...},
get{cpools}
{}
iterable_iterator & operator++() ENTT_NOEXCEPT {
return ++it, (++std::get<OIt>(owned), ...), *this;
}
iterable_iterator operator++(int) ENTT_NOEXCEPT {
iterable_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
return std::tuple_cat(
std::make_tuple(*it),
std::forward_as_tuple(*std::get<OIt>(owned)...),
get_as_tuple(*std::get<storage_type<Get> *>(get), *it)...
);
}
[[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
std::tuple<OIt...> owned;
std::tuple<storage_type<Get> *...> get;
};
public:
using iterator = iterable_iterator<
typename basic_common_type::iterator,
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().end())>>...>
>;
using reverse_iterator = iterable_iterator<
typename basic_common_type::reverse_iterator,
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().rbegin())>>...>
>;
iterable(std::tuple<storage_type<Owned> *..., storage_type<Get> *...> cpools, const std::size_t * const extent)
: pools{cpools},
length{extent}
{}
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return length ? iterator{
std::get<0>(pools)->basic_common_type::end() - *length,
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end() - *length)...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return length ? iterator{
std::get<0>(pools)->basic_common_type::end(),
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end())...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return length ? reverse_iterator{
std::get<0>(pools)->basic_common_type::rbegin(),
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin())...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return length ? reverse_iterator{
std::get<0>(pools)->basic_common_type::rbegin() + *length,
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin() + *length)...),
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
}
private:
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
const std::size_t * const length;
};
basic_group(const std::size_t &extent, storage_type<Owned> &... opool, storage_type<Get> &... gpool) ENTT_NOEXCEPT
: pools{&opool..., &gpool...},
length{&extent}
{}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator = typename basic_common_type::iterator;
/*! @brief Reversed iterator type. */
using reverse_iterator = typename basic_common_type::reverse_iterator;
/*! @brief Iterable group type. */
using iterable_group = iterable;
/*! @brief Default constructor to use to create empty, invalid groups. */
basic_group() ENTT_NOEXCEPT
: length{}
{}
/**
* @brief Returns the number of entities that have the given components.
* @return Number of entities that have the given components.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return *this ? *length : size_type{};
}
/**
* @brief Checks whether a group is empty.
* @return True if the group is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return !*this || !*length;
}
/**
* @brief Direct access to the raw representation offered by the storage.
*
* @warning
* This function is only available for owned types.
*
* @tparam Component Type of component in which one is interested.
* @return A pointer to the array of components.
*/
template<typename Component>
[[nodiscard]] auto raw() const ENTT_NOEXCEPT {
static_assert((std::is_same_v<Component, Owned> || ...), "Non-owned type");
auto *cpool = std::get<storage_type<Component> *>(pools);
return cpool ? cpool->raw() : decltype(cpool->raw()){};
}
/**
* @brief Direct access to the list of entities.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] auto data() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->data() : nullptr;
}
/**
* @brief Returns an iterator to the first entity of the group.
*
* The returned iterator points to the first entity of the group. If the
* group is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the group.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return *this ? (std::get<0>(pools)->basic_common_type::end() - *length) : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the group.
*
* The returned iterator points to the entity following the last entity of
* the group. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* group.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->basic_common_type::end() : iterator{};
}
/**
* @brief Returns an iterator to the first entity of the reversed group.
*
* The returned iterator points to the first entity of the reversed group.
* If the group is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first entity of the reversed group.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return *this ? std::get<0>(pools)->basic_common_type::rbegin() : reverse_iterator{};
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* group.
*
* The returned iterator points to the entity following the last entity of
* the reversed group. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* reversed group.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return *this ? (std::get<0>(pools)->basic_common_type::rbegin() + *length) : reverse_iterator{};
}
/**
* @brief Returns the first entity of the group, if any.
* @return The first entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type front() const {
const auto it = begin();
return it != end() ? *it : null;
}
/**
* @brief Returns the last entity of the group, if any.
* @return The last entity of the group if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type back() const {
const auto it = rbegin();
return it != rend() ? *it : null;
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const {
const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{};
return it != end() && it >= begin() && *it == entt ? it : end();
}
/**
* @brief Returns the identifier that occupies the given position.
* @param pos Position of the element to return.
* @return The identifier that occupies the given position.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const {
return begin()[pos];
}
/**
* @brief Checks if a group is properly initialized.
* @return True if the group is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return length != nullptr;
}
/**
* @brief Checks if a group contains an entity.
* @param entt A valid entity identifier.
* @return True if the group contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length));
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `registry::get` during iterations. It has
* far better performance than its counterpart.
*
* @warning
* Attempting to use an invalid component type results in a compilation
* error. Attempting to use an entity that doesn't belong to the group
* results in undefined behavior.
*
* @tparam Component Types of components to get.
* @param entt A valid entity identifier.
* @return The components assigned to the entity.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
ENTT_ASSERT(contains(entt), "Group does not contain entity");
if constexpr(sizeof...(Component) == 0) {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Owned> *>(pools), entt)..., get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
} else if constexpr(sizeof...(Component) == 1) {
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
} else {
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
}
}
/**
* @brief Iterates entities and components and applies the given function
* object to them.
*
* The function object is invoked for each entity. It is provided with the
* entity itself and a set of references to non-empty components. The
* _constness_ of the components is as requested.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entity_type, Type &...);
* void(Type &...);
* @endcode
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(auto args: each()) {
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
std::apply(func, args);
} else {
std::apply([&func](auto, auto &&... less) { func(std::forward<decltype(less)>(less)...); }, args);
}
}
}
/**
* @brief Returns an iterable object to use to _visit_ the group.
*
* The iterable object returns tuples that contain the current entity and a
* set of references to its non-empty components. The _constness_ of the
* components is as requested.
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @return An iterable object to use to _visit_ the group.
*/
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
return iterable_group{pools, length};
}
/**
* @brief Sort a group according to the given comparison function.
*
* Sort the group so that iterating it with a couple of iterators returns
* entities and components in the expected order. See `begin` and `end` for
* more details.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to one of the following:
*
* @code{.cpp}
* bool(std::tuple<Component &...>, std::tuple<Component &...>);
* bool(const Component &, const Component &);
* bool(const Entity, const Entity);
* @endcode
*
* Where `Component` are either owned types or not but still such that they
* are iterated by the group.<br/>
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function oject must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Component Optional types of components to compare.
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const {
auto *cpool = std::get<0>(pools);
if constexpr(sizeof...(Component) == 0) {
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...);
} else if constexpr(sizeof...(Component) == 1) {
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
}, std::move(algo), std::forward<Args>(args)...);
} else {
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
}, std::move(algo), std::forward<Args>(args)...);
}
[this](auto *head, auto *... other) {
for(auto next = *length; next; --next) {
const auto pos = next - 1;
[[maybe_unused]] const auto entt = head->data()[pos];
(other->swap(other->data()[pos], entt), ...);
}
}(std::get<storage_type<Owned> *>(pools)...);
}
private:
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
const size_type * const length;
};
}
#endif

View File

@ -1,168 +0,0 @@
#ifndef ENTT_ENTITY_HELPER_HPP
#define ENTT_ENTITY_HELPER_HPP
#include <type_traits>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "registry.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Converts a registry to a view.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct as_view {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
/**
* @brief Conversion function from a registry to a view.
* @tparam Exclude Types of components used to filter the view.
* @tparam Component Type of components used to construct the view.
* @return A newly created view.
*/
template<typename Exclude, typename... Component>
operator basic_view<entity_type, Exclude, Component...>() const {
return reg.template view<Component...>(Exclude{});
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(basic_registry<Entity> &) -> as_view<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(const basic_registry<Entity> &) -> as_view<const Entity>;
/**
* @brief Converts a registry to a group.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct as_group {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
/**
* @brief Conversion function from a registry to a group.
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Types of components owned by the group.
* @return A newly created group.
*/
template<typename Exclude, typename Get, typename... Owned>
operator basic_group<entity_type, Exclude, Get, Owned...>() const {
if constexpr(std::is_const_v<registry_type>) {
return reg.template group_if_exists<Owned...>(Get{}, Exclude{});
} else {
return reg.template group<Owned...>(Get{}, Exclude{});
}
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(basic_registry<Entity> &) -> as_group<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
/**
* @brief Helper to create a listener that directly invokes a member function.
* @tparam Member Member function to invoke on a component of the given type.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @param reg A registry that contains the given entity and its components.
* @param entt Entity from which to get the component.
*/
template<auto Member, typename Entity = entity>
void invoke(basic_registry<Entity> &reg, const Entity entt) {
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
delegate<void(basic_registry<Entity> &, const Entity)> func;
func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
func(reg, entt);
}
/**
* @brief Returns the entity associated with a given component.
*
* @warning
* Currently, this function only works correctly with the default pool as it
* makes assumptions about how the components are laid out.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename Entity, typename Component>
Entity to_entity(const basic_registry<Entity> &reg, const Component &instance) {
const auto view = reg.template view<const Component>();
const auto *addr = std::addressof(instance);
for(auto it = view.rbegin(), last = view.rend(); it < last; it += ENTT_PACKED_PAGE) {
if(const auto dist = (addr - std::addressof(view.template get<const Component>(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) {
return *(it + dist);
}
}
return entt::null;
}
}
#endif

View File

@ -1,60 +0,0 @@
#ifndef ENTT_ENTITY_POLY_STORAGE_HPP
#define ENTT_ENTITY_POLY_STORAGE_HPP
#include <cstddef>
#include <tuple>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../poly/poly.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Basic poly storage implementation.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct Storage: type_list<type_info() const ENTT_NOEXCEPT> {
/**
* @brief Concept definition.
* @tparam Base Opaque base class from which to inherit.
*/
template<typename Base>
struct type: Base {
/**
* @brief Returns a type info for the contained objects.
* @return The type info for the contained objects.
*/
type_info value_type() const ENTT_NOEXCEPT {
return poly_call<0>(*this);
}
};
/**
* @brief Concept implementation.
* @tparam Type Type for which to generate an implementation.
*/
template<typename Type>
using impl = value_list<&type_id<typename Type::value_type>>;
};
/**
* @brief Defines the poly storage type associate with a given entity type.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity, typename = void>
struct poly_storage_traits {
/*! @brief Poly storage type for the given entity type. */
using storage_type = poly<Storage<Entity>>;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,245 +0,0 @@
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
#include <iterator>
#include <vector>
#include <utility>
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "entity.hpp"
#include "sparse_set.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Runtime view.
*
* Runtime views iterate over those entities that have at least all the given
* components in their bags. During initialization, a runtime view looks at the
* number of entities available for each component and picks up a reference to
* the smallest set of candidate entities in order to get a performance boost
* when iterate.<br/>
* Order of elements during iterations are highly dependent on the order of the
* underlying data structures. See sparse_set and its specializations for more
* details.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
* behavior.
*
* @note
* Views share references to the underlying data structures of the registry that
* generated them. Therefore any change to the entities and to the components
* made by means of the registry are immediately reflected by the views, unless
* a pool was missing when the view was built (in this case, the view won't
* have a valid reference and won't be updated accordingly).
*
* @warning
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class basic_runtime_view final {
using basic_common_type = basic_sparse_set<Entity>;
using underlying_iterator = typename basic_common_type::iterator;
class view_iterator final {
[[nodiscard]] bool valid() const {
const auto entt = *it;
return (!stable_storage || (entt != tombstone))
&& std::all_of(pools->begin()++, pools->end(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
public:
using difference_type = typename underlying_iterator::difference_type;
using value_type = typename underlying_iterator::value_type;
using pointer = typename underlying_iterator::pointer;
using reference = typename underlying_iterator::reference;
using iterator_category = std::bidirectional_iterator_tag;
view_iterator() ENTT_NOEXCEPT = default;
view_iterator(const std::vector<const basic_common_type *> &cpools, const std::vector<const basic_common_type *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT
: pools{&cpools},
filter{&ignore},
it{curr},
stable_storage{std::any_of(pools->cbegin(), pools->cend(), [](const basic_common_type *cpool) { return (cpool->policy() == deletion_policy::in_place); })}
{
if(it != (*pools)[0]->end() && !valid()) {
++(*this);
}
}
view_iterator & operator++() {
while(++it != (*pools)[0]->end() && !valid());
return *this;
}
view_iterator operator++(int) {
view_iterator orig = *this;
return ++(*this), orig;
}
view_iterator & operator--() ENTT_NOEXCEPT {
while(--it != (*pools)[0]->begin() && !valid());
return *this;
}
view_iterator operator--(int) ENTT_NOEXCEPT {
view_iterator orig = *this;
return operator--(), orig;
}
[[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
[[nodiscard]] pointer operator->() const {
return it.operator->();
}
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
const std::vector<const basic_common_type *> *pools;
const std::vector<const basic_common_type *> *filter;
underlying_iterator it;
bool stable_storage;
};
[[nodiscard]] bool valid() const {
return !pools.empty() && pools.front();
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Bidirectional iterator type. */
using iterator = view_iterator;
/*! @brief Default constructor to use to create empty, invalid views. */
basic_runtime_view() ENTT_NOEXCEPT
: pools{},
filter{}
{}
/**
* @brief Constructs a runtime view from a set of storage classes.
* @param cpools The storage for the types to iterate.
* @param epools The storage for the types used to filter the view.
*/
basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
: pools{std::move(cpools)},
filter{std::move(epools)}
{
// brings the best candidate (if any) on front of the vector
std::rotate(pools.begin(), std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
}), pools.end());
}
/**
* @brief Estimates the number of entities iterated by the view.
* @return Estimated number of entities iterated by the view.
*/
[[nodiscard]] size_type size_hint() const {
return valid() ? pools.front()->size() : size_type{};
}
/**
* @brief Returns an iterator to the first entity that has the given
* components.
*
* The returned iterator points to the first entity that has the given
* components. If the view is empty, the returned iterator will be equal to
* `end()`.
*
* @return An iterator to the first entity that has the given components.
*/
[[nodiscard]] iterator begin() const {
return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
}
/**
* @brief Returns an iterator that is past the last entity that has the
* given components.
*
* The returned iterator points to the entity following the last entity that
* has the given components. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity that has the
* given components.
*/
[[nodiscard]] iterator end() const {
return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
}
/**
* @brief Checks if a view contains an entity.
* @param entt A valid entity identifier.
* @return True if the view contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
/**
* @brief Iterates entities and applies the given function object to them.
*
* The function object is invoked for each entity. It is provided only with
* the entity itself. To get the components, users can use the registry with
* which the view was built.<br/>
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
* void(const entity_type);
* @endcode
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(const auto entity: *this) {
func(entity);
}
}
private:
std::vector<const basic_common_type *> pools;
std::vector<const basic_common_type *> filter;
};
}
#endif

View File

@ -1,870 +0,0 @@
#ifndef ENTT_ENTITY_SPARSE_SET_HPP
#define ENTT_ENTITY_SPARSE_SET_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/fwd.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @brief Sparse set deletion policy. */
enum class deletion_policy: std::uint8_t {
/*! @brief Swap-and-pop deletion policy. */
swap_and_pop = 0u,
/*! @brief In-place deletion policy. */
in_place = 1u
};
/**
* @brief Basic sparse set implementation.
*
* Sparse set or packed array or whatever is the name users give it.<br/>
* Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
* _packed_ one; one used for direct access through contiguous memory, the other
* one used to get the data through an extra level of indirection.<br/>
* This is largely used by the registry to offer users the fastest access ever
* to the components. Views and groups in general are almost entirely designed
* around sparse sets.
*
* This type of data structure is widely documented in the literature and on the
* web. This is nothing more than a customized implementation suitable for the
* purpose of the framework.
*
* @note
* Internal data structures arrange elements to maximize performance. There are
* no guarantees that entities are returned in the insertion order when iterate
* a sparse set. Do not make assumption on the order in any case.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Entity, typename Allocator>
class basic_sparse_set {
static constexpr auto growth_factor = 1.5;
static constexpr auto sparse_page = ENTT_SPARSE_PAGE;
using traits_type = entt_traits<Entity>;
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Entity>;
using alloc_pointer = typename alloc_traits::pointer;
using alloc_const_pointer = typename alloc_traits::const_pointer;
using bucket_alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<alloc_pointer>;
using bucket_alloc_pointer = typename bucket_alloc_traits::pointer;
static_assert(alloc_traits::propagate_on_container_move_assignment::value);
static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value);
struct sparse_set_iterator final {
using difference_type = typename traits_type::difference_type;
using value_type = Entity;
using pointer = const value_type *;
using reference = const value_type &;
using iterator_category = std::random_access_iterator_tag;
sparse_set_iterator() ENTT_NOEXCEPT = default;
sparse_set_iterator(const alloc_const_pointer *ref, const difference_type idx) ENTT_NOEXCEPT
: packed{ref},
index{idx}
{}
sparse_set_iterator & operator++() ENTT_NOEXCEPT {
return --index, *this;
}
sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
iterator orig = *this;
return ++(*this), orig;
}
sparse_set_iterator & operator--() ENTT_NOEXCEPT {
return ++index, *this;
}
sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
sparse_set_iterator orig = *this;
return operator--(), orig;
}
sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
index -= value;
return *this;
}
sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
sparse_set_iterator copy = *this;
return (copy += value);
}
sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
return (*this += -value);
}
sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
return (*this + -value);
}
difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index - index;
}
[[nodiscard]] reference operator[](const difference_type value) const {
const auto pos = size_type(index-value-1u);
return (*packed)[pos];
}
[[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index == index;
}
[[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
[[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index > other.index;
}
[[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index < other.index;
}
[[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this > other);
}
[[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this < other);
}
[[nodiscard]] pointer operator->() const {
const auto pos = size_type(index-1u);
return std::addressof((*packed)[pos]);
}
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
const alloc_const_pointer *packed;
difference_type index;
};
[[nodiscard]] static auto page(const Entity entt) ENTT_NOEXCEPT {
return static_cast<size_type>(traits_type::to_entity(entt) / sparse_page);
}
[[nodiscard]] static auto offset(const Entity entt) ENTT_NOEXCEPT {
return static_cast<size_type>(traits_type::to_entity(entt) & (sparse_page - 1));
}
[[nodiscard]] auto assure_page(const std::size_t idx) {
if(!(idx < bucket)) {
const size_type sz = idx + 1u;
const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz);
std::uninitialized_value_construct(mem + bucket, mem + sz);
std::uninitialized_copy(sparse, sparse + bucket, mem);
std::destroy(sparse, sparse + bucket);
bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket);
sparse = mem;
bucket = sz;
}
if(!sparse[idx]) {
sparse[idx] = alloc_traits::allocate(allocator, sparse_page);
std::uninitialized_fill(sparse[idx], sparse[idx] + sparse_page, null);
}
return sparse[idx];
}
void resize_packed(const std::size_t req) {
ENTT_ASSERT((req != reserved) && !(req < count), "Invalid request");
const auto mem = alloc_traits::allocate(allocator, req);
std::uninitialized_copy(packed, packed + count, mem);
std::uninitialized_fill(mem + count, mem + req, tombstone);
std::destroy(packed, packed + reserved);
alloc_traits::deallocate(allocator, packed, reserved);
packed = mem;
reserved = req;
}
void release_memory() {
if(packed) {
for(size_type pos{}; pos < bucket; ++pos) {
if(sparse[pos]) {
std::destroy(sparse[pos], sparse[pos] + sparse_page);
alloc_traits::deallocate(allocator, sparse[pos], sparse_page);
}
}
std::destroy(packed, packed + reserved);
std::destroy(sparse, sparse + bucket);
alloc_traits::deallocate(allocator, packed, reserved);
bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket);
}
}
protected:
/**
* @brief Swaps two entities in the internal packed array.
* @param lhs A valid position of an entity within storage.
* @param rhs A valid position of an entity within storage.
*/
virtual void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {}
/**
* @brief Moves an entity in the internal packed array.
* @param from A valid position of an entity within storage.
* @param to A valid position of an entity within storage.
*/
virtual void move_and_pop([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) {}
/**
* @brief Attempts to erase an entity from the internal packed array.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
virtual void swap_and_pop(const Entity entt, [[maybe_unused]] void *ud) {
auto &ref = sparse[page(entt)][offset(entt)];
const auto pos = static_cast<size_type>(traits_type::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier");
auto &last = packed[--count];
packed[pos] = last;
sparse[page(last)][offset(last)] = ref;
// lazy self-assignment guard
ref = null;
// unnecessary but it helps to detect nasty bugs
ENTT_ASSERT((last = tombstone, true), "");
}
/**
* @brief Attempts to erase an entity from the internal packed array.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
virtual void in_place_pop(const Entity entt, [[maybe_unused]] void *ud) {
auto &ref = sparse[page(entt)][offset(entt)];
const auto pos = static_cast<size_type>(traits_type::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier");
packed[pos] = std::exchange(free_list, traits_type::construct(static_cast<typename traits_type::entity_type>(pos)));
// lazy self-assignment guard
ref = null;
}
public:
/*! @brief Allocator type. */
using allocator_type = typename alloc_traits::allocator_type;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Pointer type to contained entities. */
using pointer = alloc_const_pointer;
/*! @brief Random access iterator type. */
using iterator = sparse_set_iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
/**
* @brief Constructs an empty container with the given policy and allocator.
* @param pol Type of deletion policy.
* @param alloc Allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(deletion_policy pol, const allocator_type &alloc = {})
: allocator{alloc},
bucket_allocator{alloc},
sparse{bucket_alloc_traits::allocate(bucket_allocator, 0u)},
packed{alloc_traits::allocate(allocator, 0u)},
bucket{0u},
count{0u},
reserved{0u},
free_list{tombstone},
mode{pol}
{}
/**
* @brief Constructs an empty container with the given allocator.
* @param alloc Allocator to use (possibly default-constructed).
*/
explicit basic_sparse_set(const allocator_type &alloc = {})
: basic_sparse_set{deletion_policy::swap_and_pop, alloc}
{}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
: allocator{std::move(other.allocator)},
bucket_allocator{std::move(other.bucket_allocator)},
sparse{std::exchange(other.sparse, bucket_alloc_pointer{})},
packed{std::exchange(other.packed, alloc_pointer{})},
bucket{std::exchange(other.bucket, 0u)},
count{std::exchange(other.count, 0u)},
reserved{std::exchange(other.reserved, 0u)},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode}
{}
/*! @brief Default destructor. */
virtual ~basic_sparse_set() {
release_memory();
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This sparse set.
*/
basic_sparse_set & operator=(basic_sparse_set &&other) ENTT_NOEXCEPT {
release_memory();
allocator = std::move(other.allocator);
bucket_allocator = std::move(other.bucket_allocator);
sparse = std::exchange(other.sparse, bucket_alloc_pointer{});
packed = std::exchange(other.packed, alloc_pointer{});
bucket = std::exchange(other.bucket, 0u);
count = std::exchange(other.count, 0u);
reserved = std::exchange(other.reserved, 0u);
free_list = std::exchange(other.free_list, tombstone);
mode = other.mode;
return *this;
}
/**
* @brief Returns the deletion policy of a sparse set.
* @return The deletion policy of the sparse set.
*/
[[nodiscard]] deletion_policy policy() const ENTT_NOEXCEPT {
return mode;
}
/**
* @brief Returns the next slot available for insertion.
* @return The next slot available for insertion.
*/
[[nodiscard]] size_type slot() const ENTT_NOEXCEPT {
return free_list == null ? count : static_cast<size_type>(traits_type::to_entity(free_list));
}
/**
* @brief Increases the capacity of a sparse set.
*
* If the new capacity is greater than the current capacity, new storage is
* allocated, otherwise the method does nothing.
*
* @param cap Desired capacity.
*/
void reserve(const size_type cap) {
if(cap > reserved) {
resize_packed(cap);
}
}
/**
* @brief Returns the number of elements that a sparse set has currently
* allocated space for.
* @return Capacity of the sparse set.
*/
[[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
return reserved;
}
/*! @brief Requests the removal of unused capacity. */
void shrink_to_fit() {
if(count < reserved) {
resize_packed(count);
}
}
/**
* @brief Returns the extent of a sparse set.
*
* The extent of a sparse set is also the size of the internal sparse array.
* There is no guarantee that the internal packed array has the same size.
* Usually the size of the internal sparse array is equal or greater than
* the one of the internal packed array.
*
* @return Extent of the sparse set.
*/
[[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
return bucket * sparse_page;
}
/**
* @brief Returns the number of elements in a sparse set.
*
* The number of elements is also the size of the internal packed array.
* There is no guarantee that the internal sparse array has the same size.
* Usually the size of the internal sparse array is equal or greater than
* the one of the internal packed array.
*
* @return Number of elements.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return count;
}
/**
* @brief Checks whether a sparse set is empty.
* @return True if the sparse set is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return (count == size_type{});
}
/**
* @brief Direct access to the internal packed array.
* @return A pointer to the internal packed array.
*/
[[nodiscard]] pointer data() const ENTT_NOEXCEPT {
return packed;
}
/**
* @brief Returns an iterator to the beginning.
*
* The returned iterator points to the first entity of the internal packed
* array. If the sparse set is empty, the returned iterator will be equal to
* `end()`.
*
* @return An iterator to the first entity of the internal packed array.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return iterator{std::addressof(packed), static_cast<typename traits_type::difference_type>(count)};
}
/**
* @brief Returns an iterator to the end.
*
* The returned iterator points to the element following the last entity in
* the internal packed array. Attempting to dereference the returned
* iterator results in undefined behavior.
*
* @return An iterator to the element following the last entity of the
* internal packed array.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return iterator{std::addressof(packed), {}};
}
/**
* @brief Returns a reverse iterator to the beginning.
*
* The returned iterator points to the first entity of the reversed internal
* packed array. If the sparse set is empty, the returned iterator will be
* equal to `rend()`.
*
* @return An iterator to the first entity of the reversed internal packed
* array.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return std::make_reverse_iterator(end());
}
/**
* @brief Returns a reverse iterator to the end.
*
* The returned iterator points to the element following the last entity in
* the reversed internal packed array. Attempting to dereference the
* returned iterator results in undefined behavior.
*
* @return An iterator to the element following the last entity of the
* reversed internal packed array.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return std::make_reverse_iterator(begin());
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
return contains(entt) ? --(end() - index(entt)) : end();
}
/**
* @brief Checks if a sparse set contains an entity.
* @param entt A valid entity identifier.
* @return True if the sparse set contains the entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
ENTT_ASSERT(entt != tombstone && entt != null, "Invalid entity");
const auto curr = page(entt);
// testing versions permits to avoid accessing the packed array
return (curr < bucket && sparse[curr] && sparse[curr][offset(entt)] != null);
}
/**
* @brief Returns the position of an entity in a sparse set.
*
* @warning
* Attempting to get the position of an entity that doesn't belong to the
* sparse set results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The position of the entity in the sparse set.
*/
[[nodiscard]] size_type index(const entity_type entt) const ENTT_NOEXCEPT {
ENTT_ASSERT(contains(entt), "Set does not contain entity");
return static_cast<size_type>(traits_type::to_entity(sparse[page(entt)][offset(entt)]));
}
/**
* @brief Returns the entity at specified location, with bounds checking.
* @param pos The position for which to return the entity.
* @return The entity at specified location if any, a null entity otherwise.
*/
[[nodiscard]] entity_type at(const size_type pos) const ENTT_NOEXCEPT {
return pos < count ? packed[pos] : null;
}
/**
* @brief Returns the entity at specified location, without bounds checking.
* @param pos The position for which to return the entity.
* @return The entity at specified location.
*/
[[nodiscard]] entity_type operator[](const size_type pos) const ENTT_NOEXCEPT {
ENTT_ASSERT(pos < count, "Position is out of bounds");
return packed[pos];
}
/**
* @brief Appends an entity to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The slot used for insertion.
*/
size_type emplace_back(const entity_type entt) {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
if(count == reserved) {
const size_type sz = static_cast<size_type>(reserved * growth_factor);
resize_packed(sz + !(sz > reserved));
}
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count] = entt;
return count++;
}
/**
* @brief Assigns an entity to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The slot used for insertion.
*/
size_type emplace(const entity_type entt) {
if(free_list == null) {
return emplace_back(entt);
} else {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
const auto pos = static_cast<size_type>(traits_type::to_entity(free_list));
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(pos));
free_list = std::exchange(packed[pos], entt);
return pos;
}
}
/**
* @brief Assigns one or more entities to a sparse set.
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
void insert(It first, It last) {
reserve(count + std::distance(first, last));
for(; first != last; ++first) {
const auto entt = *first;
ENTT_ASSERT(!contains(entt), "Set already contains entity");
assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(count));
packed[count++] = entt;
}
}
/**
* @brief Erases an entity from a sparse set.
*
* @warning
* Attempting to erase an entity that doesn't belong to the sparse set
* results in undefined behavior.
*
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void erase(const entity_type entt, void *ud = nullptr) {
ENTT_ASSERT(contains(entt), "Set does not contain entity");
(mode == deletion_policy::in_place) ? in_place_pop(entt, ud) : swap_and_pop(entt, ud);
}
/**
* @brief Erases entities from a set.
*
* @sa erase
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
template<typename It>
void erase(It first, It last, void *ud = nullptr) {
for(; first != last; ++first) {
erase(*first, ud);
}
}
/**
* @brief Removes an entity from a sparse set if it exists.
* @param entt A valid entity identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return True if the entity is actually removed, false otherwise.
*/
bool remove(const entity_type entt, void *ud = nullptr) {
return contains(entt) && (erase(entt, ud), true);
}
/**
* @brief Removes entities from a sparse set if they exist.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return The number of entities actually removed.
*/
template<typename It>
size_type remove(It first, It last, void *ud = nullptr) {
size_type found{};
for(; first != last; ++first) {
found += remove(*first, ud);
}
return found;
}
/*! @brief Removes all tombstones from the packed array of a sparse set. */
void compact() {
size_type next = count;
for(; next && packed[next - 1u] == tombstone; --next);
for(auto *it = &free_list; *it != null && next; it = std::addressof(packed[traits_type::to_entity(*it)])) {
if(const size_type pos = traits_type::to_entity(*it); pos < next) {
--next;
move_and_pop(next, pos);
std::swap(packed[next], packed[pos]);
sparse[page(packed[pos])][offset(packed[pos])] = traits_type::construct(static_cast<const typename traits_type::entity_type>(pos));
*it = traits_type::construct(static_cast<typename traits_type::entity_type>(next));
for(; next && packed[next - 1u] == tombstone; --next);
}
}
free_list = tombstone;
count = next;
}
/**
* @copybrief swap_at
*
* For what it's worth, this function affects both the internal sparse array
* and the internal packed array. Users should not care of that anyway.
*
* @warning
* Attempting to swap entities that don't belong to the sparse set results
* in undefined behavior.
*
* @param lhs A valid entity identifier.
* @param rhs A valid entity identifier.
*/
void swap(const entity_type lhs, const entity_type rhs) {
ENTT_ASSERT(contains(lhs), "Set does not contain entity");
ENTT_ASSERT(contains(rhs), "Set does not contain entity");
auto &entt = sparse[page(lhs)][offset(lhs)];
auto &other = sparse[page(rhs)][offset(rhs)];
const auto from = static_cast<size_type>(traits_type::to_entity(entt));
const auto to = static_cast<size_type>(traits_type::to_entity(other));
// basic no-leak guarantee (with invalid state) if swapping throws
swap_at(from, to);
std::swap(entt, other);
std::swap(packed[from], packed[to]);
}
/**
* @brief Sort the first count elements according to the given comparison
* function.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to the following:
*
* @code{.cpp}
* bool(const Entity, const Entity);
* @endcode
*
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function object must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param length Number of elements to sort.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&... args) {
// basic no-leak guarantee (with invalid state) if sorting throws
ENTT_ASSERT(!(length > count), "Length exceeds the number of elements");
compact();
algo(std::make_reverse_iterator(packed + length), std::make_reverse_iterator(packed), std::move(compare), std::forward<Args>(args)...);
for(size_type pos{}; pos < length; ++pos) {
auto curr = pos;
auto next = index(packed[curr]);
while(curr != next) {
const auto idx = index(packed[next]);
const auto entt = packed[curr];
swap_at(next, idx);
sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast<typename traits_type::entity_type>(curr));
curr = std::exchange(next, idx);
}
}
}
/**
* @brief Sort all elements according to the given comparison function.
*
* @sa sort_n
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
sort_n(count, std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
/**
* @brief Sort entities according to their order in another sparse set.
*
* Entities that are part of both the sparse sets are ordered internally
* according to the order they have in `other`. All the other entities goes
* to the end of the list and there are no guarantees on their order.<br/>
* In other terms, this function can be used to impose the same order on two
* sets by using one of them as a master and the other one as a slave.
*
* Iterating the sparse set with a couple of iterators returns elements in
* the expected order after a call to `respect`. See `begin` and `end` for
* more details.
*
* @param other The sparse sets that imposes the order of the entities.
*/
void respect(const basic_sparse_set &other) {
compact();
const auto to = other.end();
auto from = other.begin();
for(size_type pos = count - 1; pos && from != to; ++from) {
if(contains(*from)) {
if(*from != packed[pos]) {
// basic no-leak guarantee (with invalid state) if swapping throws
swap(packed[pos], *from);
}
--pos;
}
}
}
/**
* @brief Clears a sparse set.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void clear(void *ud = nullptr) {
for(auto &&entity: *this) {
if(entity != tombstone) {
in_place_pop(entity, ud);
}
}
free_list = tombstone;
count = 0u;
}
private:
typename alloc_traits::allocator_type allocator;
typename bucket_alloc_traits::allocator_type bucket_allocator;
bucket_alloc_pointer sparse;
alloc_pointer packed;
std::size_t bucket;
std::size_t count;
std::size_t reserved;
entity_type free_list;
deletion_policy mode;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
#ifndef ENTT_ENTITY_UTILITY_HPP
#define ENTT_ENTITY_UTILITY_HPP
#include "../core/type_traits.hpp"
namespace entt {
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
struct exclude_t: type_list<Type...> {};
/**
* @brief Variable template for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr exclude_t<Type...> exclude{};
/**
* @brief Alias for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
struct get_t: type_list<Type...>{};
/**
* @brief Variable template for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr get_t<Type...> get{};
}
#endif

Some files were not shown because too many files have changed in this diff Show More