Compare commits
47 commits
master
...
125-game-s
Author | SHA1 | Date | |
---|---|---|---|
9286c9fe98 | |||
3a24dabdf2 | |||
09f8dda990 | |||
863332b806 | |||
1f04c5d115 | |||
2b85ba672a | |||
931d6c39a4 | |||
d70041f064 | |||
209cc3d8f5 | |||
66ca9c6fa9 | |||
50caf0464b | |||
b0cb649dff | |||
7c1793e9a2 | |||
72026a8f99 | |||
4e9e5f4730 | |||
2aedc9dae9 | |||
4042654856 | |||
a5cd7da487 | |||
4c87d4f429 | |||
d203c0bbe4 | |||
f1f22ce1f2 | |||
2ec47ae884 | |||
7df83c9877 | |||
aff98c4144 | |||
18345e775e | |||
b78c7adf39 | |||
eb0b81cf59 | |||
cc1a0acc30 | |||
7ac4c8c0ef | |||
6147a76d16 | |||
2e70bf0772 | |||
ca67b62f52 | |||
60247ce42c | |||
4982db6609 | |||
efd261be77 | |||
63ddbd707f | |||
0c2accd72c | |||
0d0b27ba49 | |||
23aef12502 | |||
b9144a3ff0 | |||
bae1f812cf | |||
1668f0f73d | |||
3615059a96 | |||
e2eb461fb3 | |||
c378ddba07 | |||
e305ce49aa | |||
e8b331059d |
115 changed files with 30445 additions and 1705 deletions
|
@ -1,4 +1,4 @@
|
||||||
; EditorConfig to support per-solution formatting.
|
; EditorConfig to support per-solution formatting.
|
||||||
; Use the EditorConfig VS add-in to make this work.
|
; Use the EditorConfig VS add-in to make this work.
|
||||||
; http://editorconfig.org/
|
; http://editorconfig.org/
|
||||||
;
|
;
|
||||||
|
@ -23,10 +23,13 @@ indent_style = space
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
file_header_template = Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
[*.(yaml|yml)]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
[*.cs]
|
[*.cs]
|
||||||
dotnet_diagnostic.MA0004.severity = none
|
dotnet_diagnostic.MA0004.severity = none
|
||||||
file_header_template = Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
dotnet_sort_system_directives_first = true
|
dotnet_sort_system_directives_first = true
|
||||||
dotnet_diagnostic.MA0007.severity = none
|
dotnet_diagnostic.MA0007.severity = none
|
||||||
|
@ -50,7 +53,7 @@ csharp_style_var_elsewhere = true:suggestion
|
||||||
csharp_style_throw_expression = false:suggestion
|
csharp_style_throw_expression = false:suggestion
|
||||||
|
|
||||||
# Newline settings
|
# Newline settings
|
||||||
csharp_new_line_before_open_brace = all
|
csharp_new_line_before_open_brace = none
|
||||||
csharp_new_line_before_else = true
|
csharp_new_line_before_else = true
|
||||||
csharp_new_line_before_catch = true
|
csharp_new_line_before_catch = true
|
||||||
csharp_new_line_before_finally = true
|
csharp_new_line_before_finally = true
|
||||||
|
|
|
@ -6,8 +6,8 @@ on:
|
||||||
- develop
|
- develop
|
||||||
- master
|
- master
|
||||||
paths:
|
paths:
|
||||||
- Wiki/**
|
- Wiki/**
|
||||||
- Wiki.Dockerfile
|
- Wiki.Dockerfile
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Name of module and id separated by a slash
|
# Name of module and id separated by a slash
|
||||||
|
@ -25,103 +25,103 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
|
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
|
||||||
steps:
|
steps:
|
||||||
- name: Sanitize branch name
|
- name: Sanitize branch name
|
||||||
id: sanitize
|
id: sanitize
|
||||||
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
|
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: registry.jetbrains.team/p/writerside/builder/writerside-builder:${{env.DOCKER_VERSION}}
|
container: registry.jetbrains.team/p/writerside/builder/writerside-builder:${{env.DOCKER_VERSION}}
|
||||||
steps:
|
steps:
|
||||||
- name: Install basic dependencies
|
- name: Install basic dependencies
|
||||||
run: |
|
run: |
|
||||||
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
|
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
|
||||||
echo "::add-path::$HOME/.nvm"
|
echo "::add-path::$HOME/.nvm"
|
||||||
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
nvm install 18
|
nvm install 18
|
||||||
nvm use 18
|
nvm use 18
|
||||||
echo "::add-path::$(dirname $(which npm))"
|
echo "::add-path::$(dirname $(which npm))"
|
||||||
nvm --version
|
nvm --version
|
||||||
- name: Check Node.js version
|
- name: Check Node.js version
|
||||||
run: |
|
run: |
|
||||||
node -v
|
node -v
|
||||||
npm -v
|
npm -v
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: https://github.com/actions/checkout@v3
|
uses: https://github.com/actions/checkout@v3
|
||||||
- name: Build docs
|
- name: Build docs
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
export DISPLAY=:99
|
export DISPLAY=:99
|
||||||
Xvfb :99 &
|
Xvfb :99 &
|
||||||
/opt/builder/bin/idea.sh helpbuilderinspect -source-dir . -product ${{env.INSTANCE}} -output-dir artifacts/ || true
|
/opt/builder/bin/idea.sh helpbuilderinspect -source-dir . -product ${{env.INSTANCE}} -output-dir artifacts/ || true
|
||||||
echo "Test existing of ${{ env.ARTIFACT }} artifact"
|
echo "Test existing of ${{ env.ARTIFACT }} artifact"
|
||||||
test -e artifacts/${{ env.ARTIFACT }}
|
test -e artifacts/${{ env.ARTIFACT }}
|
||||||
- name: rename artifact
|
- name: rename artifact
|
||||||
run: |
|
run: |
|
||||||
mv artifacts/${{ env.ARTIFACT }} artifacts/wiki.zip
|
mv artifacts/${{ env.ARTIFACT }} artifacts/wiki.zip
|
||||||
- name: Upload documentation
|
- name: Upload documentation
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: wiki.zip
|
name: wiki.zip
|
||||||
path: artifacts/wiki.zip
|
path: artifacts/wiki.zip
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
- name: Upload algolia-indexes
|
- name: Upload algolia-indexes
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: algolia-indexes.zip
|
name: algolia-indexes.zip
|
||||||
path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
|
path: artifacts/${{ env.ALGOLIA_ARTIFACT }}
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|
||||||
build-docs-container:
|
build-docs-container:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
needs: [docs, preprocess]
|
needs: [ docs, preprocess ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: https://github.com/actions/checkout@v3
|
uses: https://github.com/actions/checkout@v3
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ github.server_url }}
|
registry: ${{ github.server_url }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
- name: Retrieve docs artifact
|
- name: Retrieve docs artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wiki.zip
|
name: wiki.zip
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
- name: Unzip wiki.zip into .public
|
- name: Unzip wiki.zip into .public
|
||||||
run: |
|
run: |
|
||||||
mkdir .public
|
mkdir .public
|
||||||
unzip -jo -qq ./wiki.zip/wiki.zip -d .public
|
unzip -jo -qq ./wiki.zip/wiki.zip -d .public
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Wiki.Dockerfile
|
file: Wiki.Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki
|
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
- name: Build and push to latest
|
- name: Build and push to latest
|
||||||
if: github.ref_name == 'master'
|
if: github.ref_name == 'master'
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Wiki.Dockerfile
|
file: Wiki.Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: forge.rainote.dev/${{ github.repository }}:latest-wiki
|
tags: forge.rainote.dev/${{ github.repository }}:latest-wiki
|
||||||
platforms: linux/amd64, linux/arm64
|
platforms: linux/amd64, linux/arm64
|
||||||
|
|
||||||
deploy-wiki:
|
deploy-wiki:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
needs: [build-docs-container, docs, preprocess]
|
needs: [ build-docs-container, docs, preprocess ]
|
||||||
steps:
|
steps:
|
||||||
- name: Deploy Image to CapRrover
|
- name: Deploy Image to CapRrover
|
||||||
run: |
|
run: |
|
||||||
docker run caprover/cli-caprover:2.2.3 caprover deploy --caproverUrl ${{ secrets.CAPROVER_SERVER }} --appToken ${{ secrets.WIKI_APP_TOKEN }} --imageName forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki -a ${{ secrets.WIKI_APP_NAME }}
|
docker run caprover/cli-caprover:2.2.3 caprover deploy --caproverUrl ${{ secrets.CAPROVER_SERVER }} --appToken ${{ secrets.WIKI_APP_TOKEN }} --imageName forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}-wiki -a ${{ secrets.WIKI_APP_NAME }}
|
||||||
|
|
|
@ -3,8 +3,8 @@ run-name: ${{ gitea.actor }} is building the Server application
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- develop
|
- develop
|
||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- Wiki/**
|
- Wiki/**
|
||||||
- Benchmarks/**
|
- Benchmarks/**
|
||||||
|
@ -183,24 +183,24 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: |
|
dotnet-version: |
|
||||||
7.0
|
9.0
|
||||||
8.0
|
dotnet-quality: preview
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
dotnet restore
|
dotnet restore
|
||||||
echo "::add-path::$HOME/.dotnet/tools"
|
echo "::add-path::$HOME/.dotnet/tools"
|
||||||
- name: Install nuget-license
|
- name: Install nuget-license
|
||||||
run: dotnet tool install --global dotnet-project-licenses
|
run: dotnet tool install --global dotnet-project-licenses
|
||||||
- name: Export licenses
|
- name: Export licenses
|
||||||
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
|
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
|
||||||
- name: Upload licenses
|
- name: Upload licenses
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: licenses
|
name: licenses
|
||||||
path: licenses
|
path: licenses
|
||||||
retention-days: 31
|
retention-days: 31
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
name: PR Workflow
|
name: PR Workflow
|
||||||
run-name: ${{ gitea.actor }} PR related workflow
|
run-name: ${{ gitea.actor }} PR related workflow
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- Wiki/**
|
- Wiki/**
|
||||||
- Benchmarks/**
|
- Benchmarks/**
|
||||||
- .run/**
|
- .run/**
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
preprocess:
|
preprocess:
|
||||||
|
@ -13,158 +13,158 @@ jobs:
|
||||||
outputs:
|
outputs:
|
||||||
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
|
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
|
||||||
steps:
|
steps:
|
||||||
- name: Sanitize branch name
|
- name: Sanitize branch name
|
||||||
id: sanitize
|
id: sanitize
|
||||||
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
|
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
global-json-file: global.json
|
global-json-file: global.json
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
dotnet build Continuity.AuthServer -c Release
|
dotnet build Continuity.AuthServer -c Release
|
||||||
|
|
||||||
sbom-scan:
|
sbom-scan:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
global-json-file: global.json
|
global-json-file: global.json
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
dotnet restore
|
dotnet restore
|
||||||
echo "::add-path::$HOME/.dotnet/tools"
|
echo "::add-path::$HOME/.dotnet/tools"
|
||||||
- name: Setup Dependency Track Dependencies
|
- name: Setup Dependency Track Dependencies
|
||||||
run: |
|
run: |
|
||||||
dotnet tool install --global CycloneDX
|
dotnet tool install --global CycloneDX
|
||||||
- name: Generate SBOM
|
- name: Generate SBOM
|
||||||
run: |
|
run: |
|
||||||
dotnet CycloneDX Continuity.AuthServer/Continuity.AuthServer.csproj -o . -dgl
|
dotnet CycloneDX Continuity.AuthServer/Continuity.AuthServer.csproj -o . -dgl
|
||||||
- name: Upload SBOM
|
- name: Upload SBOM
|
||||||
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
|
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
|
||||||
with:
|
with:
|
||||||
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
|
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
|
||||||
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
|
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
|
||||||
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}
|
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}
|
||||||
autoCreate: true
|
autoCreate: true
|
||||||
# set projectversion to be the branch name
|
# set projectversion to be the branch name
|
||||||
projectVersion: ${{ github.ref_name }}
|
projectVersion: ${{ github.ref_name }}
|
||||||
bomFilename: ${{ github.workspace }}/bom.xml
|
bomFilename: ${{ github.workspace }}/bom.xml
|
||||||
|
|
||||||
container-build:
|
container-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
needs: [ build, preprocess ]
|
needs: [build, preprocess]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
global-json-file: global.json
|
global-json-file: global.json
|
||||||
# Add support for more platforms with QEMU (optional)
|
# Add support for more platforms with QEMU (optional)
|
||||||
# https://github.com/docker/setup-qemu-action
|
# https://github.com/docker/setup-qemu-action
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ github.server_url }}
|
registry: ${{ github.server_url }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Continuity.AuthServer/Dockerfile
|
file: Continuity.AuthServer/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
- name: Build and push to latest
|
- name: Build and push to latest
|
||||||
if: github.ref_name == 'master'
|
if: github.ref_name == 'master'
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Continuity.AuthServer/Dockerfile
|
file: Continuity.AuthServer/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: forge.rainote.dev/${{ github.repository }}:latest
|
tags: forge.rainote.dev/${{ github.repository }}:latest
|
||||||
platforms: linux/amd64, linux/arm64
|
platforms: linux/amd64, linux/arm64
|
||||||
|
|
||||||
container-sbom-scan:
|
container-sbom-scan:
|
||||||
needs: [ container-build, preprocess ]
|
needs: [container-build, preprocess]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
global-json-file: global.json
|
global-json-file: global.json
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
dotnet restore
|
dotnet restore
|
||||||
echo "::add-path::$HOME/.dotnet/tools"
|
echo "::add-path::$HOME/.dotnet/tools"
|
||||||
- name: Setup Dependency Track Dependencies
|
- name: Setup Dependency Track Dependencies
|
||||||
run: |
|
run: |
|
||||||
mkdir ~/.docker
|
mkdir ~/.docker
|
||||||
curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
|
curl -sSfL https://raw.githubusercontent.com/docker/sbom-cli-plugin/main/install.sh | sh -s --
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ github.server_url }}
|
registry: ${{ github.server_url }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
- name: Generate SBOM
|
- name: Generate SBOM
|
||||||
run: |
|
run: |
|
||||||
echo forge.rainote.dev/${{ github.repository }}
|
echo forge.rainote.dev/${{ github.repository }}
|
||||||
echo forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
echo forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
||||||
docker pull forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
docker pull forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
|
||||||
docker sbom -D forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }} --format cyclonedx-json --output container-bom.json
|
docker sbom -D forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }} --format cyclonedx-json --output container-bom.json
|
||||||
- name: Upload SBOM
|
- name: Upload SBOM
|
||||||
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
|
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
|
||||||
with:
|
with:
|
||||||
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
|
apiKey: ${{ secrets.DEPENDENCY_TRACK_API_KEY }}
|
||||||
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
|
serverHostname: ${{ secrets.DEPENDENCY_TRACK_URL }}
|
||||||
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}-container
|
projectName: ${{ secrets.DEPENDENCY_TRACK_PROJECT_NAME }}-container
|
||||||
autoCreate: true
|
autoCreate: true
|
||||||
# set projectversion to be the branch name
|
# set projectversion to be the branch name
|
||||||
projectVersion: ${{ github.ref_name }}
|
projectVersion: ${{ github.ref_name }}
|
||||||
bomFilename: ${{ github.workspace }}/container-bom.json
|
bomFilename: ${{ github.workspace }}/container-bom.json
|
||||||
|
|
||||||
generate-licences:
|
generate-licences:
|
||||||
needs: [ build, preprocess ]
|
needs: [build, preprocess]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
container: catthehacker/ubuntu:act-latest@sha256:5f2ff408985b10de9da4a8ea735b7f07d4f98c61608180ebb8964deb37f7580a
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: https://github.com/actions/setup-dotnet@v3
|
uses: https://github.com/actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: |
|
dotnet-version: |
|
||||||
7.0
|
9.0
|
||||||
8.0
|
dotnet-quality: preview
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
dotnet restore
|
dotnet restore
|
||||||
echo "::add-path::$HOME/.dotnet/tools"
|
echo "::add-path::$HOME/.dotnet/tools"
|
||||||
- name: Install nuget-license
|
- name: Install nuget-license
|
||||||
run: dotnet tool install --global dotnet-project-licenses
|
run: dotnet tool install --global dotnet-project-licenses
|
||||||
- name: Export licenses
|
- name: Export licenses
|
||||||
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
|
run: dotnet-project-licenses -i . -u --projects-filter projects_ignore_licenses.json -m -j -e -f licenses
|
||||||
- name: Upload licenses
|
- name: Upload licenses
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: licenses
|
name: licenses
|
||||||
path: licenses
|
path: licenses
|
||||||
retention-days: 31
|
retention-days: 31
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,7 +4,8 @@
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
licenses
|
licenses
|
||||||
|
.run
|
||||||
|
BenchmarkDotNet.Artifacts
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
*.suo
|
*.suo
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
#Use dotnet format already installed on your machine
|
#Use dotnet format already installed on your machine
|
||||||
- id: dotnet-format
|
- id: dotnet-format
|
||||||
name: dotnet-format
|
name: dotnet-format
|
||||||
language: system
|
language: system
|
||||||
entry: dotnet format --include
|
entry: dotnet format --include Continuity.slnx
|
||||||
types_or: [c#, vb]
|
types_or: [c#, vb]
|
||||||
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
|
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
|
||||||
rev: v1.6.26.11
|
rev: v1.7.6.22
|
||||||
hooks:
|
hooks:
|
||||||
- id: actionlint
|
- id: actionlint
|
||||||
additional_dependencies: [pyflakes>=3.0.1, shellcheck-py>=0.9.0.5]
|
additional_dependencies: [pyflakes>=3.0.1, shellcheck-py>=0.9.0.5]
|
||||||
- repo: https://github.com/hadolint/hadolint
|
- repo: https://github.com/hadolint/hadolint
|
||||||
rev: v2.12.0
|
rev: v2.13.1-beta
|
||||||
hooks:
|
hooks:
|
||||||
- id: hadolint-docker
|
- id: hadolint-docker
|
||||||
args: [--ignore, SC2086]
|
args: [--ignore, SC2086]
|
||||||
|
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
|
||||||
|
rev: v2.14.0
|
||||||
|
hooks:
|
||||||
|
- id: pretty-format-yaml
|
||||||
|
args: [--autofix, --indent, '2']
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Server/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
|
||||||
<deployment type="dockerfile">
|
|
||||||
<settings>
|
|
||||||
<option name="imageTag" value="continuity" />
|
|
||||||
<option name="buildCliOptions" value="--platform linux/amd64" />
|
|
||||||
<option name="buildKitEnabled" value="true" />
|
|
||||||
<option name="buildOnly" value="true" />
|
|
||||||
<option name="contextFolderPath" value="." />
|
|
||||||
<option name="sourceFilePath" value="Server/Dockerfile" />
|
|
||||||
</settings>
|
|
||||||
</deployment>
|
|
||||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="build images" type="PowerShellRunType" factoryName="PowerShell" scriptUrl="C:\Users\Timot\Projects\Continuity\build-image.ps1" workingDirectory="C:\Users\Timot\Projects\Continuity" executablePath="C:\Users\Timot\scoop\apps\pwsh\current\pwsh.exe">
|
<configuration default="false" name="build images" type="PowerShellRunType" factoryName="PowerShell" scriptUrl="$PROJECT_DIR$\build-image.ps1" workingDirectory="$PROJECT_DIR$">
|
||||||
<envs />
|
<envs />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
<settings>
|
<settings>
|
||||||
<option name="buildKitEnabledForCompose" value="true" />
|
<option name="buildKitEnabledForCompose" value="true" />
|
||||||
<option name="envFilePath" value="" />
|
<option name="envFilePath" value="" />
|
||||||
|
<option name="removeImagesOnComposeDown" value="LOCAL" />
|
||||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
<option name="upDetach" value="false" />
|
<option name="upDetach" value="false" />
|
||||||
|
<option name="upForceRecreate" value="true" />
|
||||||
<option name="upRemoveOrphans" value="true" />
|
<option name="upRemoveOrphans" value="true" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
|
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="false" isSslEnabled="false" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Build" default="false" projectName="Wonderking" projectPath="$PROJECT_DIR$/Wonderking/Wonderking.csproj" />
|
<option name="Build" default="false" projectName="Wonderking" projectPath="$PROJECT_DIR$/Wonderking/Wonderking.csproj" />
|
||||||
<option name="Build" default="false" projectName="Server" projectPath="$PROJECT_DIR$/Server/Server.csproj" />
|
<option name="Build" default="false" projectName="Server" projectPath="$PROJECT_DIR$/Server/Server.csproj" />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
@ -11,69 +11,59 @@ namespace Benchmarks;
|
||||||
|
|
||||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
[Config(typeof(GenericConfig))]
|
[Config(typeof(GenericConfig))]
|
||||||
public class Argon2Benchmarks
|
public class Argon2Benchmarks {
|
||||||
{
|
private byte[] _additionalData = null!;
|
||||||
[Params(2, 4)] public int _iterations;
|
[Params(2, 4)] public int _iterations;
|
||||||
|
[Params(16)] public int _length;
|
||||||
[Params(16, 32)] public int _memory;
|
[Params(16, 32)] public int _memory;
|
||||||
[Params(1, 2)] public int _parallelism;
|
[Params(1, 2)] public int _parallelism;
|
||||||
private byte[] _salt = null!;
|
|
||||||
private byte[] _additionalData = null!;
|
|
||||||
[Params(16)] public int _length;
|
|
||||||
|
|
||||||
private byte[] _password = null!;
|
private byte[] _password = null!;
|
||||||
|
private byte[] _salt = null!;
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
|
||||||
_salt = RandomNumberGenerator.GetBytes(16);
|
_salt = RandomNumberGenerator.GetBytes(16);
|
||||||
_additionalData = RandomNumberGenerator.GetBytes(16);
|
_additionalData = RandomNumberGenerator.GetBytes(16);
|
||||||
_password = RandomNumberGenerator.GetBytes(16);
|
_password = RandomNumberGenerator.GetBytes(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] Argon2i()
|
public byte[] Argon2i() {
|
||||||
{
|
return new Argon2i(_password) {
|
||||||
return new Argon2i(_password)
|
|
||||||
{
|
|
||||||
Iterations = _iterations,
|
Iterations = _iterations,
|
||||||
MemorySize = 1024 * _memory,
|
MemorySize = 1024 * _memory,
|
||||||
DegreeOfParallelism = _parallelism,
|
DegreeOfParallelism = _parallelism,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Salt = _salt,
|
Salt = _salt
|
||||||
}.GetBytes(_length);
|
}.GetBytes(_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] Argon2d()
|
public byte[] Argon2d() {
|
||||||
{
|
return new Argon2d(_password) {
|
||||||
return new Argon2d(_password)
|
|
||||||
{
|
|
||||||
Iterations = _iterations,
|
Iterations = _iterations,
|
||||||
MemorySize = 1024 * _memory,
|
MemorySize = 1024 * _memory,
|
||||||
DegreeOfParallelism = _parallelism,
|
DegreeOfParallelism = _parallelism,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Salt = _salt,
|
Salt = _salt
|
||||||
}.GetBytes(_length);
|
}.GetBytes(_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] Argon2id()
|
public byte[] Argon2id() {
|
||||||
{
|
return new Argon2id(_password) {
|
||||||
return new Argon2id(_password)
|
|
||||||
{
|
|
||||||
Iterations = _iterations,
|
Iterations = _iterations,
|
||||||
MemorySize = 1024 * _memory,
|
MemorySize = 1024 * _memory,
|
||||||
DegreeOfParallelism = _parallelism,
|
DegreeOfParallelism = _parallelism,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Salt = _salt,
|
Salt = _salt
|
||||||
}.GetBytes(_length);
|
}.GetBytes(_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] IsopohArgon2DD()
|
public byte[] IsopohArgon2DD() {
|
||||||
{
|
var config = new Argon2Config {
|
||||||
var config = new Argon2Config
|
|
||||||
{
|
|
||||||
Type = Argon2Type.DataDependentAddressing,
|
Type = Argon2Type.DataDependentAddressing,
|
||||||
Version = Argon2Version.Nineteen,
|
Version = Argon2Version.Nineteen,
|
||||||
MemoryCost = 1024 * _memory,
|
MemoryCost = 1024 * _memory,
|
||||||
|
@ -82,17 +72,15 @@ public class Argon2Benchmarks
|
||||||
HashLength = _length,
|
HashLength = _length,
|
||||||
Salt = _salt,
|
Salt = _salt,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Password = _password,
|
Password = _password
|
||||||
};
|
};
|
||||||
var argon2 = new Argon2(config);
|
var argon2 = new Argon2(config);
|
||||||
return argon2.Hash().Buffer;
|
return argon2.Hash().Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] IsopohArgon2DI()
|
public byte[] IsopohArgon2DI() {
|
||||||
{
|
var config = new Argon2Config {
|
||||||
var config = new Argon2Config
|
|
||||||
{
|
|
||||||
Type = Argon2Type.DataIndependentAddressing,
|
Type = Argon2Type.DataIndependentAddressing,
|
||||||
Version = Argon2Version.Nineteen,
|
Version = Argon2Version.Nineteen,
|
||||||
MemoryCost = 1024 * _memory,
|
MemoryCost = 1024 * _memory,
|
||||||
|
@ -101,17 +89,15 @@ public class Argon2Benchmarks
|
||||||
HashLength = _length,
|
HashLength = _length,
|
||||||
Salt = _salt,
|
Salt = _salt,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Password = _password,
|
Password = _password
|
||||||
};
|
};
|
||||||
var argon2 = new Argon2(config);
|
var argon2 = new Argon2(config);
|
||||||
return argon2.Hash().Buffer;
|
return argon2.Hash().Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public byte[] IsopohArgon2Hybrid()
|
public byte[] IsopohArgon2Hybrid() {
|
||||||
{
|
var config = new Argon2Config {
|
||||||
var config = new Argon2Config
|
|
||||||
{
|
|
||||||
Type = Argon2Type.HybridAddressing,
|
Type = Argon2Type.HybridAddressing,
|
||||||
Version = Argon2Version.Nineteen,
|
Version = Argon2Version.Nineteen,
|
||||||
MemoryCost = 1024 * _memory,
|
MemoryCost = 1024 * _memory,
|
||||||
|
@ -120,7 +106,7 @@ public class Argon2Benchmarks
|
||||||
HashLength = _length,
|
HashLength = _length,
|
||||||
Salt = _salt,
|
Salt = _salt,
|
||||||
AssociatedData = _additionalData,
|
AssociatedData = _additionalData,
|
||||||
Password = _password,
|
Password = _password
|
||||||
};
|
};
|
||||||
var argon2 = new Argon2(config);
|
var argon2 = new Argon2(config);
|
||||||
return argon2.Hash().Buffer;
|
return argon2.Hash().Buffer;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -13,15 +13,15 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
|
||||||
<PackageReference Include="DotNext.Unsafe" Version="0.14.0" />
|
<PackageReference Include="DotNext.Unsafe" Version="0.14.0"/>
|
||||||
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0"/>
|
||||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" />
|
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.146">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.28">
|
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
@ -9,29 +9,25 @@ namespace Benchmarks;
|
||||||
|
|
||||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
[Config(typeof(GenericConfig))]
|
[Config(typeof(GenericConfig))]
|
||||||
public class BinaryConversionBenchmarks
|
public class BinaryConversionBenchmarks {
|
||||||
{
|
|
||||||
private byte[] _data = null!;
|
private byte[] _data = null!;
|
||||||
private int _offset;
|
private int _offset;
|
||||||
private int _writeBuffer;
|
private int _writeBuffer;
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
|
||||||
_data = RandomNumberGenerator.GetBytes(4000);
|
_data = RandomNumberGenerator.GetBytes(4000);
|
||||||
_offset = RandomNumberGenerator.GetInt32(0, 3500);
|
_offset = RandomNumberGenerator.GetInt32(0, 3500);
|
||||||
_writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
|
_writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public short BitConverterParseTest()
|
public short BitConverterParseTest() {
|
||||||
{
|
|
||||||
return BitConverter.ToInt16(_data, _offset);
|
return BitConverter.ToInt16(_data, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public short BinaryReader()
|
public short BinaryReader() {
|
||||||
{
|
|
||||||
using var ms = new MemoryStream(_data);
|
using var ms = new MemoryStream(_data);
|
||||||
using var reader = new BinaryReader(ms);
|
using var reader = new BinaryReader(ms);
|
||||||
reader.BaseStream.Position = _offset;
|
reader.BaseStream.Position = _offset;
|
||||||
|
@ -39,28 +35,24 @@ public class BinaryConversionBenchmarks
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public short BinaryPrimitivesRead()
|
public short BinaryPrimitivesRead() {
|
||||||
{
|
|
||||||
return BinaryPrimitives.ReadInt16LittleEndian(
|
return BinaryPrimitives.ReadInt16LittleEndian(
|
||||||
new ArraySegment<byte>(_data, _offset, sizeof(short)));
|
new ArraySegment<byte>(_data, _offset, sizeof(short)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void BinaryPrimitivesWrite()
|
public void BinaryPrimitivesWrite() {
|
||||||
{
|
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(_data.AsSpan(_offset, 4),
|
BinaryPrimitives.WriteInt32LittleEndian(_data.AsSpan(_offset, 4),
|
||||||
_writeBuffer);
|
_writeBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void BitConverterCopy()
|
public void BitConverterCopy() {
|
||||||
{
|
|
||||||
BitConverter.GetBytes(_writeBuffer).CopyTo(_data, _offset);
|
BitConverter.GetBytes(_writeBuffer).CopyTo(_data, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void BitConverterAssignment()
|
public void BitConverterAssignment() {
|
||||||
{
|
|
||||||
var bytes = BitConverter.GetBytes(_writeBuffer);
|
var bytes = BitConverter.GetBytes(_writeBuffer);
|
||||||
_data[_offset] = bytes[0];
|
_data[_offset] = bytes[0];
|
||||||
_data[_offset + 1] = bytes[1];
|
_data[_offset + 1] = bytes[1];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
@ -9,17 +9,15 @@ namespace Benchmarks;
|
||||||
|
|
||||||
[Config(typeof(GenericConfig))]
|
[Config(typeof(GenericConfig))]
|
||||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
public class DataCacheBenchmark
|
public class DataCacheBenchmark {
|
||||||
{
|
private ConcurrentDictionary<int, int> _concurrentDictionary = null!;
|
||||||
private ConcurrentDictionary<int, int> _concurrentDictionary;
|
private Dictionary<int, int> _dictionary = null!;
|
||||||
private Dictionary<int, int> _dictionary;
|
private HashSet<int> _hashSet = null!;
|
||||||
private HashSet<int> _hashSet;
|
private ImmutableHashSet<int> _immutableHashSet = null!;
|
||||||
private ImmutableHashSet<int> _immutableHashSet;
|
|
||||||
[Params(1000, 100000, 1000000)] public int N;
|
[Params(1000, 100000, 1000000)] public int N;
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup() {
|
||||||
{
|
|
||||||
_hashSet = new HashSet<int>();
|
_hashSet = new HashSet<int>();
|
||||||
_dictionary = new Dictionary<int, int>();
|
_dictionary = new Dictionary<int, int>();
|
||||||
_concurrentDictionary = new ConcurrentDictionary<int, int>();
|
_concurrentDictionary = new ConcurrentDictionary<int, int>();
|
||||||
|
@ -32,8 +30,7 @@ public class DataCacheBenchmark
|
||||||
_hashSet.EnsureCapacity(N);
|
_hashSet.EnsureCapacity(N);
|
||||||
_dictionary.EnsureCapacity(N);
|
_dictionary.EnsureCapacity(N);
|
||||||
|
|
||||||
for (var i = 0; i < N; i++)
|
for (var i = 0; i < N; i++) {
|
||||||
{
|
|
||||||
_immutableHashSet = _immutableHashSet.Add(i);
|
_immutableHashSet = _immutableHashSet.Add(i);
|
||||||
_hashSet.Add(i);
|
_hashSet.Add(i);
|
||||||
_dictionary.Add(i, i);
|
_dictionary.Add(i, i);
|
||||||
|
@ -42,45 +39,38 @@ public class DataCacheBenchmark
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void HashSetAdd()
|
public void HashSetAdd() {
|
||||||
{
|
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Add(i));
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Add(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void DictionaryAdd()
|
public void DictionaryAdd() {
|
||||||
{
|
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.Add(N + i, i));
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.Add(N + i, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void ConcurrentDictionaryAddOrUpdate()
|
public void ConcurrentDictionaryAddOrUpdate() {
|
||||||
{
|
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i =>
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i =>
|
||||||
_concurrentDictionary.AddOrUpdate(N + i, i, (key, oldValue) => oldValue + i));
|
_concurrentDictionary.AddOrUpdate(N + i, i, (_, oldValue) => oldValue + i));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void ImmutableHashSetLookup()
|
public void ImmutableHashSetLookup() {
|
||||||
{
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _immutableHashSet.Contains(i); });
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _immutableHashSet.Contains(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void HashSetLookup()
|
public void HashSetLookup() {
|
||||||
{
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _hashSet.Contains(i); });
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Contains(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void DictionaryLookup()
|
public void DictionaryLookup() {
|
||||||
{
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _dictionary.ContainsKey(i); });
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.ContainsKey(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void ConcurrentDictionaryLookup()
|
public void ConcurrentDictionaryLookup() {
|
||||||
{
|
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _concurrentDictionary.ContainsKey(i); });
|
||||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _concurrentDictionary.ContainsKey(i));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using BenchmarkDotNet.Analysers;
|
using BenchmarkDotNet.Analysers;
|
||||||
using BenchmarkDotNet.Columns;
|
using BenchmarkDotNet.Columns;
|
||||||
|
@ -11,10 +11,8 @@ using BenchmarkDotNet.Jobs;
|
||||||
|
|
||||||
namespace Benchmarks;
|
namespace Benchmarks;
|
||||||
|
|
||||||
public class GenericConfig : ManualConfig
|
public class GenericConfig : ManualConfig {
|
||||||
{
|
public GenericConfig() {
|
||||||
public GenericConfig()
|
|
||||||
{
|
|
||||||
AddJob(Job.Default
|
AddJob(Job.Default
|
||||||
.WithRuntime(CoreRuntime.Core80))
|
.WithRuntime(CoreRuntime.Core80))
|
||||||
.AddDiagnoser(ThreadingDiagnoser.Default, MemoryDiagnoser.Default,
|
.AddDiagnoser(ThreadingDiagnoser.Default, MemoryDiagnoser.Default,
|
||||||
|
|
163
Benchmarks/MemCasting.cs
Normal file
163
Benchmarks/MemCasting.cs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Order;
|
||||||
|
|
||||||
|
namespace Benchmarks;
|
||||||
|
|
||||||
|
[Config(typeof(GenericConfig))]
|
||||||
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
|
public class MemCasting {
|
||||||
|
private byte[] _data = null!;
|
||||||
|
private byte[] _arrayData = null!;
|
||||||
|
|
||||||
|
[Params(1000, 100000, 1000000)] public int N;
|
||||||
|
[GlobalSetup]
|
||||||
|
public void Setup() {
|
||||||
|
_data = new byte[64];
|
||||||
|
_arrayData = new byte[N * 64];
|
||||||
|
Random.Shared.NextBytes(_data);
|
||||||
|
Random.Shared.NextBytes(_arrayData);
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsMemoryMarshal(ref Span<byte> data) {
|
||||||
|
return MemoryMarshal.Cast<byte, ElementalStats>(data.Slice(0, 64))[0];
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsMemoryMarshal2(ref Span<byte> data) {
|
||||||
|
return MemoryMarshal.Read<ElementalStats>(data.Slice(0, 64));
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsNew(ref Span<byte> data) {
|
||||||
|
return new ElementalStats {
|
||||||
|
MinimumFireDamage = BitConverter.ToInt32(data.Slice(0, 4)), // 140 -> 144
|
||||||
|
MinimumWaterDamage = BitConverter.ToInt32(data.Slice(4, 4)), // 144 -> 148
|
||||||
|
MinimumDarkDamage = BitConverter.ToInt32(data.Slice(8, 4)), // 148 -> 152
|
||||||
|
MinimumHolyDamage = BitConverter.ToInt32(data.Slice(12, 4)), // 152 -> 156
|
||||||
|
MaximumFireDamage = BitConverter.ToInt32(data.Slice(16, 4)), // 156 -> 160
|
||||||
|
MaximumWaterDamage = BitConverter.ToInt32(data.Slice(20, 4)), // 160 -> 164
|
||||||
|
MaximumDarkDamage = BitConverter.ToInt32(data.Slice(24, 4)), // 164 -> 168
|
||||||
|
MaximumHolyDamage = BitConverter.ToInt32(data.Slice(28, 4)), // 168 -> 172
|
||||||
|
ElementFire = BitConverter.ToUInt32(data.Slice(32, 4)), // 172 -> 176
|
||||||
|
ElementWater = BitConverter.ToUInt32(data.Slice(36, 4)), // 176 -> 180
|
||||||
|
ElementDark = BitConverter.ToUInt32(data.Slice(40, 4)), // 180 -> 184
|
||||||
|
ElementHoly = BitConverter.ToUInt32(data.Slice(44, 4)), // 184 -> 188
|
||||||
|
FireResistance = BitConverter.ToInt32(data.Slice(48, 4)), // 188 -> 192
|
||||||
|
WaterResistance = BitConverter.ToInt32(data.Slice(52, 4)), // 192 -> 196
|
||||||
|
DarkResistance = BitConverter.ToInt32(data.Slice(56, 4)), // 196 -> 200
|
||||||
|
HolyResistance = BitConverter.ToInt32(data.Slice(60, 4)) // 200 -> 204
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> MemoryMarshalCastArray() {
|
||||||
|
var data = _arrayData.AsSpan();
|
||||||
|
var elements = MemoryMarshal.Cast<byte, ElementalStats>(data);
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> MemoryMarshalReadArray() {
|
||||||
|
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
for (int i = 0; i <= N; i++) {
|
||||||
|
statsArr[i] = ReadElementalStatsMemoryMarshal2(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statsArr.ToArray();
|
||||||
|
}
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> ManualSpanSlicingArray() {
|
||||||
|
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
for (int i = 0; i <= N; i++) {
|
||||||
|
statsArr[i] = ReadElementalStatsNew(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statsArr.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats MemoryMarshalCastSingle() {
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsMemoryMarshal(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats MemoryMarshalReadSingle() {
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsMemoryMarshal2(ref data);
|
||||||
|
}
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats ManualSpanSlicingSingle() {
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsNew(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||||
|
public struct ElementalStats {
|
||||||
|
[FieldOffset(0)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumFireDamage;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumWaterDamage;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumDarkDamage;
|
||||||
|
|
||||||
|
[FieldOffset(12)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumHolyDamage;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumFireDamage;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumWaterDamage;
|
||||||
|
|
||||||
|
[FieldOffset(24)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumDarkDamage;
|
||||||
|
|
||||||
|
[FieldOffset(28)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumHolyDamage;
|
||||||
|
|
||||||
|
[FieldOffset(32)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementFire;
|
||||||
|
|
||||||
|
[FieldOffset(36)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementWater;
|
||||||
|
|
||||||
|
[FieldOffset(40)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementDark;
|
||||||
|
|
||||||
|
[FieldOffset(44)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementHoly;
|
||||||
|
|
||||||
|
[FieldOffset(48)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int FireResistance;
|
||||||
|
|
||||||
|
[FieldOffset(52)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int WaterResistance;
|
||||||
|
|
||||||
|
[FieldOffset(56)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int DarkResistance;
|
||||||
|
|
||||||
|
[FieldOffset(60)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int HolyResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BenchmarkDotNet.Running;
|
using BenchmarkDotNet.Running;
|
||||||
|
|
|
@ -1,46 +1,37 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
|
||||||
using Continuity.AuthServer.Packets;
|
using Continuity.AuthServer.Packets;
|
||||||
using MassTransit.Mediator;
|
using MassTransit.Mediator;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NetCoreServer;
|
using NetCoreServer;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets;
|
using Wonderking.Packets;
|
||||||
|
|
||||||
namespace Continuity.AuthServer;
|
namespace Continuity.AuthServer;
|
||||||
|
|
||||||
public class AuthSession : TcpSession
|
public class AuthSession : TcpSession {
|
||||||
{
|
private readonly PacketDistributorService<OperationCode, AuthSession> _distributorService;
|
||||||
private readonly ILogger<AuthSession> _logger;
|
private readonly ILogger<AuthSession> _logger;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
public AuthSession(TcpServer
|
public AuthSession(TcpServer
|
||||||
server, IMediator mediator, ILogger<AuthSession> logger) : base(server)
|
server, IMediator mediator, ILogger<AuthSession> logger,
|
||||||
{
|
PacketDistributorService<OperationCode, AuthSession> distributorService) : base(server) {
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_distributorService = distributorService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid AccountId { get; set; }
|
public Guid AccountId { get; set; }
|
||||||
|
|
||||||
public override long Send(byte[] buffer)
|
public override long Send(byte[] buffer) {
|
||||||
{
|
|
||||||
_logger.LogInformation("Data being sent is: {Data}", BitConverter.ToString(buffer));
|
_logger.LogInformation("Data being sent is: {Data}", BitConverter.ToString(buffer));
|
||||||
return base.Send(buffer);
|
return base.Send(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendAsync(IPacket packet)
|
public Task SendAsync(IOutgoingPacket packet) {
|
||||||
{
|
var opcode = _distributorService.GetOperationCodeByPacketType(packet);
|
||||||
var type = packet.GetType();
|
|
||||||
_logger.LogInformation("Packet of type {Type} is being serialized", type.Name);
|
|
||||||
var packetIdAttribute = type.GetCustomAttribute<PacketIdAttribute>();
|
|
||||||
if (packetIdAttribute == null)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var opcode = packetIdAttribute.Code;
|
|
||||||
|
|
||||||
Span<byte> packetData = packet.Serialize();
|
Span<byte> packetData = packet.Serialize();
|
||||||
var length = (ushort)(packetData.Length + 8);
|
var length = (ushort)(packetData.Length + 8);
|
||||||
|
@ -51,13 +42,11 @@ public class AuthSession : TcpSession
|
||||||
|
|
||||||
var bytesOfLength = BitConverter.GetBytes(length);
|
var bytesOfLength = BitConverter.GetBytes(length);
|
||||||
var bytesOfOpcode = BitConverter.GetBytes((ushort)opcode);
|
var bytesOfOpcode = BitConverter.GetBytes((ushort)opcode);
|
||||||
for (var i = 0; i < bytesOfLength.Length || i < 2; i++)
|
for (var i = 0; i < bytesOfLength.Length || i < 2; i++) {
|
||||||
{
|
|
||||||
buffer[i] = bytesOfLength[i];
|
buffer[i] = bytesOfLength[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++)
|
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++) {
|
||||||
{
|
|
||||||
buffer[2 + i] = bytesOfOpcode[i];
|
buffer[2 + i] = bytesOfOpcode[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +57,7 @@ public class AuthSession : TcpSession
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReceived(byte[] buffer, long offset, long size)
|
protected override void OnReceived(byte[] buffer, long offset, long size) {
|
||||||
{
|
|
||||||
_logger.LogDebug("Length: {Size} & offset: {Offset}", size, offset);
|
_logger.LogDebug("Length: {Size} & offset: {Offset}", size, offset);
|
||||||
Span<byte> decryptedBuffer = stackalloc byte[(int)size];
|
Span<byte> decryptedBuffer = stackalloc byte[(int)size];
|
||||||
|
|
||||||
|
@ -98,18 +86,15 @@ public class AuthSession : TcpSession
|
||||||
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
|
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Span<byte> Decrypt(Span<byte> buffer)
|
private static Span<byte> Decrypt(Span<byte> buffer) {
|
||||||
{
|
for (var i = 0; i < buffer.Length; ++i) {
|
||||||
for (var i = 0; i < buffer.Length; ++i)
|
|
||||||
{
|
|
||||||
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnError(SocketError error)
|
protected override void OnError(SocketError error) {
|
||||||
{
|
|
||||||
_logger.LogWarning("An error has occured: {Error}", error);
|
_logger.LogWarning("An error has occured: {Error}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -8,8 +8,7 @@ using NetCoreServer;
|
||||||
|
|
||||||
namespace Continuity.AuthServer;
|
namespace Continuity.AuthServer;
|
||||||
|
|
||||||
public class ChannelSession : TcpSession
|
public class ChannelSession : TcpSession {
|
||||||
{
|
|
||||||
private static readonly byte[] _key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
|
private static readonly byte[] _key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
|
||||||
.Reverse().ToArray();
|
.Reverse().ToArray();
|
||||||
|
|
||||||
|
@ -23,12 +22,12 @@ public class ChannelSession : TcpSession
|
||||||
private readonly ICryptoTransform _encryptor;
|
private readonly ICryptoTransform _encryptor;
|
||||||
private readonly ILogger<ChannelSession> _logger;
|
private readonly ILogger<ChannelSession> _logger;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server)
|
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server) {
|
||||||
{
|
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
var aes = Aes.Create();
|
using var aes = Aes.Create();
|
||||||
aes.Key = _key;
|
aes.Key = _key;
|
||||||
aes.IV = _iv;
|
aes.IV = _iv;
|
||||||
aes.Padding = PaddingMode.None;
|
aes.Padding = PaddingMode.None;
|
||||||
|
@ -40,33 +39,44 @@ public class ChannelSession : TcpSession
|
||||||
_encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
_encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReceived(byte[] buffer, long offset, long size)
|
protected override void OnReceived(byte[] buffer, long offset, long size) {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var ms = new MemoryStream(Decrypt(buffer)))
|
using (var ms = new MemoryStream(Decrypt(buffer)))
|
||||||
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read))
|
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read)) {
|
||||||
{
|
|
||||||
var amountOfReadBytes = cs.Read(buffer);
|
var amountOfReadBytes = cs.Read(buffer);
|
||||||
if (amountOfReadBytes != buffer.Length)
|
if (amountOfReadBytes != buffer.Length) {
|
||||||
{
|
|
||||||
_logger.LogError("Amount of read bytes is not equal to buffer length");
|
_logger.LogError("Amount of read bytes is not equal to buffer length");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnReceived(buffer, offset, size);
|
base.OnReceived(buffer, offset, size);
|
||||||
}
|
}
|
||||||
catch (CryptographicException ex)
|
catch (CryptographicException ex) {
|
||||||
{
|
|
||||||
_logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
|
_logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
|
||||||
_logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
|
_logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] Decrypt(byte[] buffer)
|
protected override void Dispose(bool disposingManagedResources) {
|
||||||
{
|
if (_disposed) {
|
||||||
for (var i = 0; i < buffer.Length; ++i)
|
return;
|
||||||
{
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
if (disposingManagedResources) {
|
||||||
|
_decryptor.Dispose();
|
||||||
|
_encryptor.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposingManagedResources);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ThrowIfDisposed() {
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] Decrypt(byte[] buffer) {
|
||||||
|
for (var i = 0; i < buffer.Length; ++i) {
|
||||||
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
using Continuity.AuthServer.Packets;
|
using Continuity.AuthServer.Packets;
|
||||||
using Continuity.AuthServer.Services;
|
using JetBrains.Annotations;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
using Wonderking.Packets;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.Consumers;
|
namespace Continuity.AuthServer.Consumers;
|
||||||
|
|
||||||
public class PacketConsumer : IConsumer<RawPacket>
|
[UsedImplicitly]
|
||||||
{
|
public sealed class PacketConsumer : IConsumer<RawPacket>, IDisposable {
|
||||||
private readonly PacketDistributorService _distributorService;
|
private readonly ActivitySource _activitySource;
|
||||||
|
private readonly PacketDistributorService<OperationCode, AuthSession> _distributorService;
|
||||||
|
|
||||||
public PacketConsumer(PacketDistributorService distributorService)
|
public PacketConsumer(PacketDistributorService<OperationCode, AuthSession> distributorService) {
|
||||||
{
|
|
||||||
_distributorService = distributorService;
|
_distributorService = distributorService;
|
||||||
|
_activitySource = new ActivitySource(nameof(PacketConsumer));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Consume(ConsumeContext<RawPacket> context)
|
public async Task Consume(ConsumeContext<RawPacket> context) {
|
||||||
{
|
using var activity = _activitySource?.StartActivity("PacketConsumption");
|
||||||
_distributorService.AddPacket(context.Message);
|
activity?.SetTag("PacketId", context.Message.OperationCode.ToString());
|
||||||
return Task.CompletedTask;
|
activity?.SetTag("SessionId", context.Message.Session.Id.ToString());
|
||||||
|
activity?.SetTag("PacketSize", context.Message.MessageBody.Length);
|
||||||
|
|
||||||
|
await _distributorService.AddPacketAsync(context.Message.MessageBody, context.Message.OperationCode,
|
||||||
|
context.Message.Session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
_activitySource.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||||
|
@ -40,66 +40,68 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="DotNext" Version="5.3.1" />
|
<PackageReference Include="DotNext" Version="5.17.2" />
|
||||||
<PackageReference Include="DotNext.IO" Version="5.3.0" />
|
<PackageReference Include="DotNext.IO" Version="5.17.2" />
|
||||||
<PackageReference Include="DotNext.Metaprogramming" Version="5.3.0" />
|
<PackageReference Include="DotNext.Metaprogramming" Version="5.17.2" />
|
||||||
<PackageReference Include="DotNext.Threading" Version="5.3.0" />
|
<PackageReference Include="DotNext.Threading" Version="5.17.2" />
|
||||||
<PackageReference Include="DotNext.Unsafe" Version="5.3.0" />
|
<PackageReference Include="DotNext.Unsafe" Version="5.17.2" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/>
|
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0"/>
|
|
||||||
<PackageReference Include="MassTransit" Version="8.1.3" />
|
|
||||||
<PackageReference Include="MassTransit.Analyzers" Version="8.1.3">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.146">
|
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||||
|
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
|
||||||
|
<PackageReference Include="MassTransit" Version="8.3.4" />
|
||||||
|
<PackageReference Include="MassTransit.Analyzers" Version="8.3.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.186">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="9.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0"/>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.9.28">
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NetCoreServer" Version="8.0.7" />
|
<PackageReference Include="NetCoreServer" Version="8.0.7" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
|
||||||
<PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.2" />
|
<PackageReference Include="Npgsql.OpenTelemetry" Version="9.0.2" />
|
||||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6169">
|
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6495">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="OpenTelemetry" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry" Version="1.11.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.11.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.11.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.12" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.10"/>
|
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.7.1" />
|
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.0.0-alpha.6" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.0.0-alpha.6" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.7.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.10.0" />
|
||||||
<PackageReference Include="OpenTelemetry.PersistentStorage.FileSystem" Version="1.0.0"/>
|
<PackageReference Include="OpenTelemetry.PersistentStorage.FileSystem" Version="1.0.0" />
|
||||||
<PackageReference Include="OpenTelemetry.ResourceDetectors.Container" Version="1.0.0-beta.6"/>
|
<PackageReference Include="OpenTelemetry.ResourceDetectors.Container" Version="1.0.0-beta.7" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0"/>
|
<PackageReference Include="RaiNote.PacketMediator" Version="0.0.7" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -116,6 +118,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Wonderking\Wonderking.csproj"/>
|
<ProjectReference Include="..\Wonderking\Wonderking.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -8,10 +8,8 @@ namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
[Index(nameof(Username), IsUnique = true)]
|
[Index(nameof(Username), IsUnique = true)]
|
||||||
[Index(nameof(Id), IsUnique = true)]
|
[Index(nameof(Id), IsUnique = true)]
|
||||||
public class Account
|
public class Account {
|
||||||
{
|
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt) {
|
||||||
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt)
|
|
||||||
{
|
|
||||||
Username = username;
|
Username = username;
|
||||||
Password = password;
|
Password = password;
|
||||||
Email = email;
|
Email = email;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -10,8 +10,7 @@ namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
[Index(nameof(Name), IsUnique = true)]
|
[Index(nameof(Name), IsUnique = true)]
|
||||||
[Index(nameof(Id), IsUnique = true)]
|
[Index(nameof(Id), IsUnique = true)]
|
||||||
public class Character
|
public class Character {
|
||||||
{
|
|
||||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||||
[Required]
|
[Required]
|
||||||
public virtual Account Account { get; set; }
|
public virtual Account Account { get; set; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -8,8 +8,7 @@ namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
[Index(nameof(Name), IsUnique = true)]
|
[Index(nameof(Name), IsUnique = true)]
|
||||||
[Index(nameof(Id), IsUnique = true)]
|
[Index(nameof(Id), IsUnique = true)]
|
||||||
public class Guild
|
public class Guild {
|
||||||
{
|
|
||||||
[Key]
|
[Key]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -7,8 +7,7 @@ using Microsoft.EntityFrameworkCore;
|
||||||
namespace Continuity.AuthServer.DB.Documents;
|
namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
[Index(nameof(Id), IsUnique = true)]
|
[Index(nameof(Id), IsUnique = true)]
|
||||||
public class GuildMember
|
public class GuildMember {
|
||||||
{
|
|
||||||
[Key]
|
[Key]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Continuity.AuthServer.DB.Documents;
|
namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
public enum GuildRank : byte
|
public enum GuildRank : byte {
|
||||||
{
|
|
||||||
Initiate = 0,
|
Initiate = 0,
|
||||||
Member = 1,
|
Member = 1,
|
||||||
Veteran = 2,
|
Veteran = 2,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
@ -6,8 +6,7 @@ using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.DB.Documents;
|
namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
public class InventoryItem
|
public class InventoryItem {
|
||||||
{
|
|
||||||
[DeleteBehavior(DeleteBehavior.Restrict)]
|
[DeleteBehavior(DeleteBehavior.Restrict)]
|
||||||
[Required]
|
[Required]
|
||||||
public virtual Character Character { get; set; }
|
public virtual Character Character { get; set; }
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Continuity.AuthServer.DB.Documents;
|
namespace Continuity.AuthServer.DB.Documents;
|
||||||
|
|
||||||
public enum InventoryTab : byte
|
public enum InventoryTab : byte {
|
||||||
{
|
|
||||||
WornEquipment = 0,
|
WornEquipment = 0,
|
||||||
WornCashEquipment = 1,
|
WornCashEquipment = 1,
|
||||||
Equipment = 2,
|
Equipment = 2,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
@ -6,13 +6,11 @@ namespace Server.DB.Migrations;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class Initial : Migration
|
public partial class Initial : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.CreateTable(
|
protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.CreateTable(
|
||||||
name: "Accounts",
|
name: "Accounts",
|
||||||
columns: table => new
|
columns: table => new {
|
||||||
{
|
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
Username = table.Column<string>(type: "varchar(20)", nullable: false),
|
Username = table.Column<string>(type: "varchar(20)", nullable: false),
|
||||||
Password = table.Column<byte[]>(type: "bytea", nullable: false),
|
Password = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
@ -6,11 +6,9 @@ namespace Server.DB.Migrations;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class CharacterDataDraft : Migration
|
public partial class CharacterDataDraft : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "Username",
|
name: "Username",
|
||||||
table: "Accounts",
|
table: "Accounts",
|
||||||
|
@ -45,8 +43,7 @@ public partial class CharacterDataDraft : Migration
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Characters",
|
name: "Characters",
|
||||||
columns: table => new
|
columns: table => new {
|
||||||
{
|
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
ServerId = table.Column<byte>(type: "smallint", nullable: false),
|
ServerId = table.Column<byte>(type: "smallint", nullable: false),
|
||||||
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
|
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
@ -59,8 +56,7 @@ public partial class CharacterDataDraft : Migration
|
||||||
Experience = table.Column<long>(type: "bigint", nullable: false),
|
Experience = table.Column<long>(type: "bigint", nullable: false),
|
||||||
Level = table.Column<byte>(type: "smallint", nullable: false)
|
Level = table.Column<byte>(type: "smallint", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table => {
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Characters", x => x.Id);
|
table.PrimaryKey("PK_Characters", x => x.Id);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
|
@ -77,8 +73,7 @@ public partial class CharacterDataDraft : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Characters");
|
name: "Characters");
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,15 +7,12 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddInventoryToCharacter : Migration
|
public partial class AddInventoryToCharacter : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "InventoryItem",
|
name: "InventoryItem",
|
||||||
columns: table => new
|
columns: table => new {
|
||||||
{
|
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
ItemId = table.Column<short>(type: "smallint", nullable: false),
|
ItemId = table.Column<short>(type: "smallint", nullable: false),
|
||||||
|
@ -31,8 +28,7 @@ public partial class AddInventoryToCharacter : Migration
|
||||||
Option2 = table.Column<short>(type: "smallint", nullable: false),
|
Option2 = table.Column<short>(type: "smallint", nullable: false),
|
||||||
Option3 = table.Column<short>(type: "smallint", nullable: false)
|
Option3 = table.Column<short>(type: "smallint", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table => {
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_InventoryItem", x => x.Id);
|
table.PrimaryKey("PK_InventoryItem", x => x.Id);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_InventoryItem_Characters_CharacterId",
|
name: "FK_InventoryItem_Characters_CharacterId",
|
||||||
|
@ -49,8 +45,7 @@ public partial class AddInventoryToCharacter : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "InventoryItem");
|
name: "InventoryItem");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AdditionalCharacterData : Migration
|
public partial class AdditionalCharacterData : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<int>(
|
migrationBuilder.AlterColumn<int>(
|
||||||
name: "ItemId",
|
name: "ItemId",
|
||||||
table: "InventoryItem",
|
table: "InventoryItem",
|
||||||
|
@ -96,8 +94,7 @@ public partial class AdditionalCharacterData : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
migrationBuilder.DropColumn(
|
||||||
name: "BaseStats_Dexterity",
|
name: "BaseStats_Dexterity",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class AddGuildData : Migration
|
public partial class AddGuildData : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<Guid>(
|
migrationBuilder.AddColumn<Guid>(
|
||||||
name: "GuildId",
|
name: "GuildId",
|
||||||
table: "Characters",
|
table: "Characters",
|
||||||
|
@ -21,28 +19,24 @@ public partial class AddGuildData : Migration
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Guild",
|
name: "Guild",
|
||||||
columns: table => new
|
columns: table => new {
|
||||||
{
|
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
Name = table.Column<string>(type: "text", nullable: true),
|
Name = table.Column<string>(type: "text", nullable: true),
|
||||||
Notice = table.Column<string>(type: "text", nullable: true)
|
Notice = table.Column<string>(type: "text", nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table => {
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Guild", x => x.Id);
|
table.PrimaryKey("PK_Guild", x => x.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "GuildMember",
|
name: "GuildMember",
|
||||||
columns: table => new
|
columns: table => new {
|
||||||
{
|
|
||||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
GuildId = table.Column<Guid>(type: "uuid", nullable: false),
|
GuildId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
Rank = table.Column<byte>(type: "smallint", nullable: false)
|
Rank = table.Column<byte>(type: "smallint", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table => {
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_GuildMember", x => x.Id);
|
table.PrimaryKey("PK_GuildMember", x => x.Id);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_GuildMember_Characters_CharacterId",
|
name: "FK_GuildMember_Characters_CharacterId",
|
||||||
|
@ -95,8 +89,7 @@ public partial class AddGuildData : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Guild_GuildId",
|
name: "FK_Characters_Guild_GuildId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class GuildIsNotRequired : Migration
|
public partial class GuildIsNotRequired : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.RenameColumn(
|
migrationBuilder.RenameColumn(
|
||||||
name: "ItemType",
|
name: "ItemType",
|
||||||
table: "InventoryItem",
|
table: "InventoryItem",
|
||||||
|
@ -19,8 +17,7 @@ public partial class GuildIsNotRequired : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.RenameColumn(
|
migrationBuilder.RenameColumn(
|
||||||
name: "InventoryTab",
|
name: "InventoryTab",
|
||||||
table: "InventoryItem",
|
table: "InventoryItem",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class SwitchToDataAnnotations : Migration
|
public partial class SwitchToDataAnnotations : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
@ -113,8 +111,7 @@ public partial class SwitchToDataAnnotations : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class DBPoolingAndLazyLoadingSupport : Migration
|
public partial class DBPoolingAndLazyLoadingSupport : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
migrationBuilder.AlterColumn<string>(
|
||||||
name: "Name",
|
name: "Name",
|
||||||
table: "Characters",
|
table: "Characters",
|
||||||
|
@ -36,8 +34,7 @@ public partial class DBPoolingAndLazyLoadingSupport : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropIndex(
|
migrationBuilder.DropIndex(
|
||||||
name: "IX_Characters_Id",
|
name: "IX_Characters_Id",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class FixInventoryItemAsDbset : Migration
|
public partial class FixInventoryItemAsDbset : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Guild_GuildId",
|
name: "FK_Characters_Guild_GuildId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
@ -86,8 +84,7 @@ public partial class FixInventoryItemAsDbset : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Guilds_GuildId",
|
name: "FK_Characters_Guilds_GuildId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class MissingCascadeDeletionOnCharacter : Migration
|
public partial class MissingCascadeDeletionOnCharacter : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_InventoryItems_Characters_CharacterId",
|
name: "FK_InventoryItems_Characters_CharacterId",
|
||||||
table: "InventoryItems");
|
table: "InventoryItems");
|
||||||
|
@ -26,8 +24,7 @@ public partial class MissingCascadeDeletionOnCharacter : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_InventoryItems_Characters_CharacterId",
|
name: "FK_InventoryItems_Characters_CharacterId",
|
||||||
table: "InventoryItems");
|
table: "InventoryItems");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class IndexingAndVariousOtherAnnotations : Migration
|
public partial class IndexingAndVariousOtherAnnotations : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
@ -112,8 +110,7 @@ public partial class IndexingAndVariousOtherAnnotations : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class VariousDeletionBehaviours : Migration
|
public partial class VariousDeletionBehaviours : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Characters_Accounts_AccountId",
|
name: "FK_Characters_Accounts_AccountId",
|
||||||
table: "Characters");
|
table: "Characters");
|
||||||
|
@ -45,8 +43,7 @@ public partial class VariousDeletionBehaviours : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Accounts_GuildMember_GuildMemberId",
|
name: "FK_Accounts_GuildMember_GuildMemberId",
|
||||||
table: "Accounts");
|
table: "Accounts");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
namespace Server.DB.Migrations;
|
namespace Server.DB.Migrations;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class FixEntityRelationships : Migration
|
public partial class FixEntityRelationships : Migration {
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
migrationBuilder.DropForeignKey(
|
||||||
name: "FK_Accounts_GuildMember_GuildMemberId",
|
name: "FK_Accounts_GuildMember_GuildMemberId",
|
||||||
table: "Accounts");
|
table: "Accounts");
|
||||||
|
@ -88,8 +86,7 @@ public partial class FixEntityRelationships : Migration
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||||
{
|
|
||||||
migrationBuilder.DropIndex(
|
migrationBuilder.DropIndex(
|
||||||
name: "IX_GuildMember_CharacterId",
|
name: "IX_GuildMember_CharacterId",
|
||||||
table: "GuildMember");
|
table: "GuildMember");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB.Documents;
|
using Continuity.AuthServer.DB.Documents;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
@ -6,14 +6,21 @@ using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.DB;
|
namespace Continuity.AuthServer.DB;
|
||||||
|
|
||||||
public class WonderkingContext : DbContext
|
public class WonderkingContext : DbContext {
|
||||||
{
|
public WonderkingContext([NotNull] DbContextOptions options) : base(options) {
|
||||||
public WonderkingContext([NotNull] DbContextOptions options) : base(options)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Account> Accounts { get; set; }
|
public DbSet<Account> Accounts { get; set; }
|
||||||
public DbSet<Character> Characters { get; set; }
|
public DbSet<Character> Characters { get; set; }
|
||||||
public DbSet<InventoryItem> InventoryItems { get; set; }
|
public DbSet<InventoryItem> InventoryItems { get; set; }
|
||||||
public DbSet<Guild> Guilds { get; set; }
|
public DbSet<Guild> Guilds { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
modelBuilder.Entity<Account>(entity => {
|
||||||
|
entity.HasIndex(e => e.Username).IsUnique();
|
||||||
|
entity.HasIndex(e => e.Id).IsUnique();
|
||||||
|
entity.Property(e => e.Id).HasColumnType("uuid");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.PacketHandlers;
|
using Continuity.AuthServer.PacketHandlers;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.LoggerMessages;
|
namespace Continuity.AuthServer.LoggerMessages;
|
||||||
|
|
||||||
internal static partial class LoginHandlerLoggerMessages
|
internal static partial class LoginHandlerLoggerMessages {
|
||||||
{
|
|
||||||
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
||||||
Message = "Login data: Username {Username} & Password {Password}")]
|
Message = "Login data: Username {Username} & Password {Password}")]
|
||||||
public static partial void LoginData(this ILogger<LoginHandler> logger, string username, string password);
|
public static partial void LoginData(this ILogger<LoginHandler> logger, string username, string password);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -6,8 +6,7 @@ using Wonderking.Packets;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.LoggerMessages;
|
namespace Continuity.AuthServer.LoggerMessages;
|
||||||
|
|
||||||
internal static partial class PacketLoggerMessages
|
internal static partial class PacketLoggerMessages {
|
||||||
{
|
|
||||||
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
||||||
Message = "Packet creation function created for {PacketID}")]
|
Message = "Packet creation function created for {PacketID}")]
|
||||||
public static partial void PacketCreationFunctionCreated(this ILogger logger, OperationCode packetId);
|
public static partial void PacketCreationFunctionCreated(this ILogger logger, OperationCode packetId);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB.Documents;
|
using Continuity.AuthServer.DB.Documents;
|
||||||
using Wonderking.Game.Data.Character;
|
using Wonderking.Game.Data.Character;
|
||||||
|
@ -6,8 +6,7 @@ using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public partial class ChannelSelectionHandler
|
public partial class ChannelSelectionHandler {
|
||||||
{
|
|
||||||
private sealed record InventoryItemProjection(ushort ItemId, byte Slot, InventoryTab InventoryTab);
|
private sealed record InventoryItemProjection(ushort ItemId, byte Slot, InventoryTab InventoryTab);
|
||||||
|
|
||||||
private sealed record CharacterDataProjection(
|
private sealed record CharacterDataProjection(
|
||||||
|
|
|
@ -1,67 +1,56 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB;
|
using Continuity.AuthServer.DB;
|
||||||
using Continuity.AuthServer.DB.Documents;
|
using Continuity.AuthServer.DB.Documents;
|
||||||
using DotNext.Collections.Generic;
|
using DotNext.Collections.Generic;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NetCoreServer;
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
using Wonderking.Packets.Outgoing;
|
using Wonderking.Packets.Outgoing;
|
||||||
using Wonderking.Packets.Outgoing.Data;
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
|
public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket, AuthSession> {
|
||||||
{
|
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
|
|
||||||
public ChannelSelectionHandler(WonderkingContext wonderkingContext)
|
public ChannelSelectionHandler(WonderkingContext wonderkingContext) {
|
||||||
{
|
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(ChannelSelectionPacket packet, TcpSession session)
|
public async Task HandleAsync(ChannelSelectionPacket packet, AuthSession session,
|
||||||
{
|
CancellationToken cancellationToken) {
|
||||||
if (session is not AuthSession authSession)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelSelectionResponsePacket responsePacket;
|
ChannelSelectionResponsePacket responsePacket;
|
||||||
var guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket { GuildNames = Array.Empty<string>() };
|
var guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket { GuildNames = Array.Empty<string>() };
|
||||||
|
|
||||||
var accountExists =
|
var accountExists =
|
||||||
await _wonderkingContext.Accounts.AsNoTracking().AnyAsync(a => a.Id == authSession.AccountId);
|
await _wonderkingContext.Accounts.AsNoTracking()
|
||||||
|
.AnyAsync(a => a.Id == session.AccountId, cancellationToken);
|
||||||
|
|
||||||
var amountOfCharacter = await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account)
|
var amountOfCharacter = await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account)
|
||||||
.Where(c => c.Account.Id == authSession.AccountId).Take(3)
|
.Where(c => c.Account.Id == session.AccountId).Take(3)
|
||||||
.CountAsync();
|
.CountAsync(cancellationToken);
|
||||||
|
|
||||||
if (!accountExists)
|
if (!accountExists) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amountOfCharacter > 0)
|
if (amountOfCharacter > 0) {
|
||||||
{
|
responsePacket = new ChannelSelectionResponsePacket {
|
||||||
responsePacket = new ChannelSelectionResponsePacket
|
|
||||||
{
|
|
||||||
ChannelIsFullFlag = 0,
|
ChannelIsFullFlag = 0,
|
||||||
Endpoint = "127.0.0.1",
|
Endpoint = "127.0.0.1",
|
||||||
Port = 2000,
|
Port = 2000,
|
||||||
Characters = await GetCharacterDataAsync(authSession.AccountId).ToArrayAsync()
|
Characters = await GetCharacterDataAsync(session.AccountId).ToArrayAsync(token: cancellationToken)
|
||||||
};
|
};
|
||||||
|
|
||||||
guildNameResponsePacket.GuildNames =
|
guildNameResponsePacket.GuildNames =
|
||||||
await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account).Include(c => c.GuildMember)
|
await _wonderkingContext.Characters.AsNoTracking().Include(c => c.Account).Include(c => c.GuildMember)
|
||||||
.ThenInclude(gm => gm.Guild)
|
.ThenInclude(gm => gm.Guild)
|
||||||
.Where(c => c.Account.Id == authSession.AccountId && c.GuildMember.Guild != null)
|
.Where(c => c.Account.Id == session.AccountId && c.GuildMember.Guild != null)
|
||||||
.Select(c => c.GuildMember.Guild.Name).Take(3).ToArrayAsync();
|
.Select(c => c.GuildMember.Guild.Name).Take(3).ToArrayAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
responsePacket = new ChannelSelectionResponsePacket {
|
||||||
responsePacket = new ChannelSelectionResponsePacket
|
|
||||||
{
|
|
||||||
ChannelIsFullFlag = 0,
|
ChannelIsFullFlag = 0,
|
||||||
Endpoint = "127.0.0.1",
|
Endpoint = "127.0.0.1",
|
||||||
Port = 2000,
|
Port = 2000,
|
||||||
|
@ -69,23 +58,19 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
await authSession.SendAsync(responsePacket);
|
await session.SendAsync(responsePacket);
|
||||||
if (guildNameResponsePacket.GuildNames.Length > 0 &&
|
if (guildNameResponsePacket.GuildNames.Length > 0 &&
|
||||||
guildNameResponsePacket.GuildNames.Select(n => n != string.Empty).Any())
|
guildNameResponsePacket.GuildNames.Select(n => n != string.Empty).Any()) {
|
||||||
{
|
await session.SendAsync(guildNameResponsePacket);
|
||||||
await authSession.SendAsync(guildNameResponsePacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<InventoryItemProjection> items)
|
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<InventoryItemProjection> items) {
|
||||||
{
|
|
||||||
var ids = new ushort[20];
|
var ids = new ushort[20];
|
||||||
ids.AsSpan().Clear();
|
ids.AsSpan().Clear();
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items) {
|
||||||
{
|
if (item.Slot > 20) {
|
||||||
if (item.Slot > 20)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +80,7 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async IAsyncEnumerable<CharacterData> GetCharacterDataAsync(Guid accountId)
|
private async IAsyncEnumerable<CharacterData> GetCharacterDataAsync(Guid accountId) {
|
||||||
{
|
|
||||||
var characterDataProjections = _wonderkingContext.Characters.AsNoTracking().AsSplitQuery()
|
var characterDataProjections = _wonderkingContext.Characters.AsNoTracking().AsSplitQuery()
|
||||||
.Include(c => c.InventoryItems).Include(c => c.Account)
|
.Include(c => c.InventoryItems).Include(c => c.Account)
|
||||||
.Where(c => c.Account.Id == accountId)
|
.Where(c => c.Account.Id == accountId)
|
||||||
|
@ -113,10 +97,8 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
||||||
new InventoryItemProjection(i.ItemId, i.Slot, i.InventoryTab))
|
new InventoryItemProjection(i.ItemId, i.Slot, i.InventoryTab))
|
||||||
)).Take(3);
|
)).Take(3);
|
||||||
|
|
||||||
await foreach (var c in characterDataProjections)
|
await foreach (var c in characterDataProjections) {
|
||||||
{
|
yield return new CharacterData {
|
||||||
yield return new CharacterData
|
|
||||||
{
|
|
||||||
Name = c.Name,
|
Name = c.Name,
|
||||||
Job = c.JobData,
|
Job = c.JobData,
|
||||||
Gender = c.Gender,
|
Gender = c.Gender,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB;
|
using Continuity.AuthServer.DB;
|
||||||
using Continuity.AuthServer.DB.Documents;
|
using Continuity.AuthServer.DB.Documents;
|
||||||
using Continuity.AuthServer.Services;
|
using Continuity.AuthServer.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NetCoreServer;
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Game.Data.Character;
|
using Wonderking.Game.Data.Character;
|
||||||
using Wonderking.Game.Mapping;
|
using Wonderking.Game.Mapping;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
|
@ -13,31 +13,24 @@ using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket, AuthSession> {
|
||||||
{
|
|
||||||
private readonly CharacterStatsMappingConfiguration _characterStatsMapping;
|
private readonly CharacterStatsMappingConfiguration _characterStatsMapping;
|
||||||
private readonly ItemObjectPoolService _itemObjectPoolService;
|
private readonly ItemObjectPoolService _itemObjectPoolService;
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
|
|
||||||
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService,
|
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService,
|
||||||
CharacterStatsMappingConfiguration characterStatsMappingConfiguration)
|
CharacterStatsMappingConfiguration characterStatsMappingConfiguration) {
|
||||||
{
|
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
_itemObjectPoolService = itemObjectPoolService;
|
_itemObjectPoolService = itemObjectPoolService;
|
||||||
_characterStatsMapping = characterStatsMappingConfiguration;
|
_characterStatsMapping = characterStatsMappingConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(CharacterCreationPacket packet, TcpSession session)
|
public async Task HandleAsync(CharacterCreationPacket packet, AuthSession session,
|
||||||
{
|
CancellationToken cancellationToken) {
|
||||||
if (session is not AuthSession authSession)
|
var account =
|
||||||
{
|
await _wonderkingContext.Accounts.Include(a => a.Characters).FirstOrDefaultAsync(a => a.Id == session.AccountId, cancellationToken);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Id == authSession.AccountId);
|
if (account is null) {
|
||||||
|
|
||||||
if (account is null)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +39,10 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
|
|
||||||
var toBeAddedCharacter = CreateDefaultCharacter(packet, account, items, firstJobConfig);
|
var toBeAddedCharacter = CreateDefaultCharacter(packet, account, items, firstJobConfig);
|
||||||
account.Characters.Add(toBeAddedCharacter);
|
account.Characters.Add(toBeAddedCharacter);
|
||||||
await _wonderkingContext.SaveChangesAsync();
|
await _wonderkingContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
var character =
|
var character =
|
||||||
new CharacterData
|
new CharacterData {
|
||||||
{
|
|
||||||
Name = toBeAddedCharacter.Name,
|
Name = toBeAddedCharacter.Name,
|
||||||
Job = toBeAddedCharacter.JobData,
|
Job = toBeAddedCharacter.JobData,
|
||||||
Gender = toBeAddedCharacter.Gender,
|
Gender = toBeAddedCharacter.Gender,
|
||||||
|
@ -68,16 +60,14 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
.Select(item => new Tuple<ushort, byte>(item.ItemId, item.Slot)).AsEnumerable())
|
.Select(item => new Tuple<ushort, byte>(item.ItemId, item.Slot)).AsEnumerable())
|
||||||
};
|
};
|
||||||
|
|
||||||
await authSession.SendAsync(new CharacterCreationResponsePacket
|
await session.SendAsync(new CharacterCreationResponsePacket {
|
||||||
{
|
|
||||||
Character = character,
|
Character = character,
|
||||||
Slot = packet.Slot,
|
Slot = packet.Slot,
|
||||||
isDuplicate = false
|
isDuplicate = false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private InventoryItem[] CreateDefaultItems(CharacterCreationPacket packet, JobSpecificMapping firstJobConfig)
|
private InventoryItem[] CreateDefaultItems(CharacterCreationPacket packet, JobSpecificMapping firstJobConfig) {
|
||||||
{
|
|
||||||
var mappedDefaultItems = _characterStatsMapping.DefaultCharacterMapping.Items
|
var mappedDefaultItems = _characterStatsMapping.DefaultCharacterMapping.Items
|
||||||
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
|
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
|
||||||
|
|
||||||
|
@ -94,10 +84,8 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Character CreateDefaultCharacter(CharacterCreationPacket packet, Account account,
|
private static Character CreateDefaultCharacter(CharacterCreationPacket packet, Account account,
|
||||||
InventoryItem[] items, JobSpecificMapping firstJobConfig)
|
InventoryItem[] items, JobSpecificMapping firstJobConfig) {
|
||||||
{
|
return new Character {
|
||||||
return new Character()
|
|
||||||
{
|
|
||||||
Account = account,
|
Account = account,
|
||||||
MapId = 300,
|
MapId = 300,
|
||||||
Name = packet.Name,
|
Name = packet.Name,
|
||||||
|
@ -115,10 +103,8 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobSpecificMapping SelectFirstJobConfig(byte firstJob)
|
private JobSpecificMapping SelectFirstJobConfig(byte firstJob) {
|
||||||
{
|
return firstJob switch {
|
||||||
return firstJob switch
|
|
||||||
{
|
|
||||||
1 => _characterStatsMapping.Swordsman,
|
1 => _characterStatsMapping.Swordsman,
|
||||||
2 => _characterStatsMapping.Mage,
|
2 => _characterStatsMapping.Mage,
|
||||||
3 => _characterStatsMapping.Thief,
|
3 => _characterStatsMapping.Thief,
|
||||||
|
@ -127,8 +113,7 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private InventoryItem[] CreateChosenItems(CharacterCreationPacket packet)
|
private InventoryItem[] CreateChosenItems(CharacterCreationPacket packet) {
|
||||||
{
|
|
||||||
return new[]
|
return new[]
|
||||||
{
|
{
|
||||||
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
|
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
|
||||||
|
@ -144,27 +129,22 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig)
|
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig) {
|
||||||
{
|
|
||||||
return (int)((level - 1) * firstJobConfig.DynamicStats.HealthPerLevel +
|
return (int)((level - 1) * firstJobConfig.DynamicStats.HealthPerLevel +
|
||||||
firstJobConfig.BaseStats.Vitality * firstJobConfig.DynamicStats.HealthPerVitality);
|
firstJobConfig.BaseStats.Vitality * firstJobConfig.DynamicStats.HealthPerVitality);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig)
|
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig) {
|
||||||
{
|
|
||||||
return (int)((level - 1) * firstJobConfig.DynamicStats.ManaPerLevel +
|
return (int)((level - 1) * firstJobConfig.DynamicStats.ManaPerLevel +
|
||||||
firstJobConfig.BaseStats.Wisdom * firstJobConfig.DynamicStats.ManaPerWisdom);
|
firstJobConfig.BaseStats.Wisdom * firstJobConfig.DynamicStats.ManaPerWisdom);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<Tuple<ushort, byte>> items)
|
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<Tuple<ushort, byte>> items) {
|
||||||
{
|
|
||||||
Span<ushort> ids = stackalloc ushort[20];
|
Span<ushort> ids = stackalloc ushort[20];
|
||||||
ids.Clear();
|
ids.Clear();
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items) {
|
||||||
{
|
if (item.Item2 > 20) {
|
||||||
if (item.Item2 > 20)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,34 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB;
|
using Continuity.AuthServer.DB;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NetCoreServer;
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
using Wonderking.Packets.Outgoing;
|
using Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket>
|
public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket, AuthSession> {
|
||||||
{
|
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
|
|
||||||
public CharacterDeletionHandler(WonderkingContext wonderkingContext)
|
public CharacterDeletionHandler(WonderkingContext wonderkingContext) {
|
||||||
{
|
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(CharacterDeletePacket packet, TcpSession session)
|
public async Task HandleAsync(CharacterDeletePacket packet, AuthSession session,
|
||||||
{
|
CancellationToken cancellationToken) {
|
||||||
if (session is not AuthSession authSession)
|
|
||||||
{
|
|
||||||
session.Disconnect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name &&
|
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name &&
|
||||||
x.Account.Id == authSession.AccountId);
|
x.Account.Id == session.AccountId, cancellationToken);
|
||||||
|
|
||||||
var response = new CharacterDeleteResponsePacket { HasToBeZero = 0 };
|
var response = new CharacterDeleteResponsePacket { HasToBeZero = 0 };
|
||||||
if (character == null)
|
if (character == null) {
|
||||||
{
|
await session.SendAsync(response);
|
||||||
await authSession.SendAsync(response);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_wonderkingContext.Characters.Remove(character);
|
_wonderkingContext.Characters.Remove(character);
|
||||||
await _wonderkingContext.SaveChangesAsync();
|
await _wonderkingContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
await authSession.SendAsync(response);
|
await session.SendAsync(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct CharacterMappingItemEntry
|
public struct CharacterMappingItemEntry {
|
||||||
{
|
|
||||||
public required ushort Id { get; set; }
|
public required ushort Id { get; set; }
|
||||||
public required ushort Quantity { get; set; }
|
public required ushort Quantity { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Continuity.AuthServer.DB;
|
using Continuity.AuthServer.DB;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NetCoreServer;
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
using Wonderking.Packets.Outgoing;
|
using Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public class CharacterNameCheckHandler : IPacketHandler<CharacterNameCheckPacket>
|
public class CharacterNameCheckHandler : IPacketHandler<CharacterNameCheckPacket, AuthSession> {
|
||||||
{
|
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
|
|
||||||
public CharacterNameCheckHandler(WonderkingContext wonderkingContext)
|
public CharacterNameCheckHandler(WonderkingContext wonderkingContext) {
|
||||||
{
|
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(CharacterNameCheckPacket packet, TcpSession session)
|
public async Task HandleAsync(CharacterNameCheckPacket packet, AuthSession session,
|
||||||
{
|
CancellationToken cancellationToken) {
|
||||||
var isTaken = await _wonderkingContext.Characters.AnyAsync(c => c.Name == packet.Name);
|
var isTaken =
|
||||||
|
await _wonderkingContext.Characters.AnyAsync(c => c.Name == packet.Name,
|
||||||
|
cancellationToken);
|
||||||
var responsePacket = new CharacterNameCheckPacketResponse { IsTaken = isTaken };
|
var responsePacket = new CharacterNameCheckPacketResponse { IsTaken = isTaken };
|
||||||
if (session is AuthSession authSession)
|
|
||||||
{
|
await session.SendAsync(responsePacket);
|
||||||
await authSession.SendAsync(responsePacket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using NetCoreServer;
|
|
||||||
using Wonderking.Packets;
|
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
|
||||||
|
|
||||||
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
|
||||||
public interface IPacketHandler<in T> : IPacketHandler where T : IPacket
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public Task HandleAsync(T packet, TcpSession session);
|
|
||||||
|
|
||||||
async Task<bool> IPacketHandler.TryHandleAsync(IPacket packet, TcpSession session)
|
|
||||||
{
|
|
||||||
if (packet is not T tPacket)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var activity = new ActivitySource(nameof(Server)).StartActivity("HandleAsync"))
|
|
||||||
{
|
|
||||||
activity?.SetTag("Handler", this.ToString());
|
|
||||||
activity?.SetTag("PacketId", packet.ToString());
|
|
||||||
await HandleAsync(tPacket, session);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IPacketHandler
|
|
||||||
{
|
|
||||||
Task<bool> TryHandleAsync(IPacket packet, TcpSession session);
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
@ -10,48 +10,44 @@ using Konscious.Security.Cryptography;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NetCoreServer;
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Incoming;
|
using Wonderking.Packets.Incoming;
|
||||||
using Wonderking.Packets.Outgoing;
|
using Wonderking.Packets.Outgoing;
|
||||||
using Wonderking.Packets.Outgoing.Data;
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.PacketHandlers;
|
namespace Continuity.AuthServer.PacketHandlers;
|
||||||
|
|
||||||
public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession> {
|
||||||
{
|
private static readonly ActivitySource _activitySource = new(nameof(Server));
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private readonly ILogger<LoginHandler> _logger;
|
private readonly ILogger<LoginHandler> _logger;
|
||||||
private readonly WonderkingContext _wonderkingContext;
|
private readonly WonderkingContext _wonderkingContext;
|
||||||
private static readonly ActivitySource _activitySource = new ActivitySource(nameof(Server));
|
|
||||||
|
|
||||||
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration)
|
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration) {
|
||||||
{
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_wonderkingContext = wonderkingContext;
|
_wonderkingContext = wonderkingContext;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(LoginInfoPacket packet, TcpSession session)
|
public async Task HandleAsync(LoginInfoPacket packet, AuthSession session, CancellationToken cancellationToken) {
|
||||||
{
|
|
||||||
LoginResponseReason loginResponseReason;
|
LoginResponseReason loginResponseReason;
|
||||||
_logger.LoginData(packet.Username, packet.Password);
|
_logger.LoginData(packet.Username, packet.Password);
|
||||||
var account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username);
|
var account =
|
||||||
|
await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
if (account == null)
|
if (account == null) {
|
||||||
{
|
if (_configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin")) {
|
||||||
if (_configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
|
|
||||||
{
|
|
||||||
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password);
|
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password);
|
||||||
account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username);
|
account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username,
|
||||||
|
cancellationToken);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
_logger.RequestedAccountDoesNotExist(packet.Username);
|
_logger.RequestedAccountDoesNotExist(packet.Username);
|
||||||
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
var salt = account.Salt;
|
var salt = account.Salt;
|
||||||
var tempPasswordBytes = await GetPasswordHashAsync(packet.Password, salt, account.Id);
|
var tempPasswordBytes = await GetPasswordHashAsync(packet.Password, salt, account.Id);
|
||||||
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
||||||
|
@ -61,50 +57,41 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
||||||
|
|
||||||
var channelData = new ServerChannelData[1];
|
var channelData = new ServerChannelData[1];
|
||||||
channelData[0] = new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 };
|
channelData[0] = new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 };
|
||||||
var loginResponsePacket = new LoginResponsePacket
|
var loginResponsePacket = new LoginResponsePacket {
|
||||||
{
|
|
||||||
ResponseReason = loginResponseReason,
|
ResponseReason = loginResponseReason,
|
||||||
ChannelData = channelData.ToArray(),
|
ChannelData = channelData.ToArray(),
|
||||||
UnknownFlag = 1,
|
UnknownFlag = 1,
|
||||||
IsGameMaster = true
|
IsGameMaster = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var authSession = session as AuthSession;
|
if (account != null) {
|
||||||
if (account != null && authSession != null)
|
session.AccountId = account.Id;
|
||||||
{
|
|
||||||
authSession.AccountId = account.Id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket);
|
_logger.LogInformation("LoginResponsePacket: {@LoginResponsePacket}", loginResponsePacket);
|
||||||
_ = authSession?.SendAsync(loginResponsePacket);
|
_ = session.SendAsync(loginResponsePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId)
|
private static async Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId) {
|
||||||
{
|
using var activity = _activitySource.StartActivity();
|
||||||
using var activity = _activitySource.StartActivity("GetPasswordHashAsync");
|
|
||||||
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Chea1t_Sheet.html#argon2id
|
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Chea1t_Sheet.html#argon2id
|
||||||
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
|
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
|
||||||
var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(password))
|
using var argon2Id = new Argon2id(Encoding.ASCII.GetBytes(password));
|
||||||
{
|
argon2Id.MemorySize = 1024 * 19;
|
||||||
MemorySize = 1024 * 19,
|
argon2Id.Iterations = 2;
|
||||||
Iterations = 2,
|
argon2Id.DegreeOfParallelism = 1;
|
||||||
DegreeOfParallelism = 1,
|
argon2Id.Salt = salt;
|
||||||
Salt = salt,
|
argon2Id.AssociatedData = userId.ToByteArray();
|
||||||
AssociatedData = userId.ToByteArray()
|
|
||||||
};
|
|
||||||
return await argon2Id.GetBytesAsync(16);
|
return await argon2Id.GetBytesAsync(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password)
|
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password) {
|
||||||
{
|
using var activity = _activitySource.StartActivity();
|
||||||
using var activity = _activitySource.StartActivity("CreateAccountOnLoginAsync");
|
|
||||||
LoginResponseReason loginResponseReason;
|
LoginResponseReason loginResponseReason;
|
||||||
var transaction =
|
var transaction =
|
||||||
await _wonderkingContext.Database.BeginTransactionAsync();
|
await _wonderkingContext.Database.BeginTransactionAsync();
|
||||||
await using (transaction)
|
await using (transaction) {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
var salt = RandomNumberGenerator.GetBytes(16);
|
var salt = RandomNumberGenerator.GetBytes(16);
|
||||||
var finalAccount = await _wonderkingContext.Accounts.AddAsync(new Account(username,
|
var finalAccount = await _wonderkingContext.Accounts.AddAsync(new Account(username,
|
||||||
Array.Empty<byte>(), "", 0, salt));
|
Array.Empty<byte>(), "", 0, salt));
|
||||||
|
@ -117,8 +104,7 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
|
||||||
|
|
||||||
await transaction.CommitAsync();
|
await transaction.CommitAsync();
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception) {
|
||||||
{
|
|
||||||
await transaction.RollbackAsync(); // Rollback the transaction on error
|
await transaction.RollbackAsync(); // Rollback the transaction on error
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Wonderking.Packets;
|
using Wonderking.Packets;
|
||||||
|
@ -6,11 +6,9 @@ using Wonderking.Packets;
|
||||||
namespace Continuity.AuthServer.Packets;
|
namespace Continuity.AuthServer.Packets;
|
||||||
|
|
||||||
[MessageUrn("packets")]
|
[MessageUrn("packets")]
|
||||||
public class RawPacket
|
public class RawPacket {
|
||||||
{
|
|
||||||
public RawPacket(OperationCode operationCode, Span<byte> messageBody, uint aliveTime, byte unknownValue2,
|
public RawPacket(OperationCode operationCode, Span<byte> messageBody, uint aliveTime, byte unknownValue2,
|
||||||
byte unknownValue, Guid sessionId, AuthSession session)
|
byte unknownValue, Guid sessionId, AuthSession session) {
|
||||||
{
|
|
||||||
MessageBody = messageBody.ToArray();
|
MessageBody = messageBody.ToArray();
|
||||||
UnknownValue2 = unknownValue2;
|
UnknownValue2 = unknownValue2;
|
||||||
UnknownValue = unknownValue;
|
UnknownValue = unknownValue;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Continuity.AuthServer;
|
||||||
using Continuity.AuthServer.DB;
|
using Continuity.AuthServer.DB;
|
||||||
|
using Continuity.AuthServer.PacketHandlers;
|
||||||
using Continuity.AuthServer.Services;
|
using Continuity.AuthServer.Services;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -17,7 +19,9 @@ using OpenTelemetry.Logs;
|
||||||
using OpenTelemetry.Metrics;
|
using OpenTelemetry.Metrics;
|
||||||
using OpenTelemetry.Resources;
|
using OpenTelemetry.Resources;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Game.Mapping;
|
using Wonderking.Game.Mapping;
|
||||||
|
using Wonderking.Packets;
|
||||||
|
|
||||||
var builder = Host.CreateApplicationBuilder();
|
var builder = Host.CreateApplicationBuilder();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -31,70 +35,43 @@ builder.Configuration.AddJsonFile("settings.json", true, true)
|
||||||
.AddEnvironmentVariables().Build();
|
.AddEnvironmentVariables().Build();
|
||||||
|
|
||||||
builder.Services.AddLogging();
|
builder.Services.AddLogging();
|
||||||
var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
var loggerFactory = LoggerFactory.Create(loggingBuilder => {
|
||||||
{
|
|
||||||
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.log", LogLevel.Trace);
|
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.log", LogLevel.Trace);
|
||||||
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.json.log", LogLevel.Trace, isJson: true);
|
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.json.log", LogLevel.Trace, isJson: true);
|
||||||
loggingBuilder.AddConsole();
|
loggingBuilder.AddConsole();
|
||||||
});
|
loggingBuilder.AddOpenTelemetry(logging => {
|
||||||
|
logging.AddOtlpExporter();
|
||||||
var configuration = builder.Configuration;
|
|
||||||
if (configuration.GetValue<bool>("Tracing:Enabled"))
|
|
||||||
{
|
|
||||||
Action<ResourceBuilder> resourceBuilderAction = r => r
|
|
||||||
.AddService("Continuity", serviceInstanceId: Environment.MachineName);
|
|
||||||
|
|
||||||
builder.Services.AddOpenTelemetry()
|
|
||||||
.ConfigureResource(resourceBuilderAction)
|
|
||||||
.WithTracing(tracing =>
|
|
||||||
{
|
|
||||||
tracing.AddSource(nameof(Server));
|
|
||||||
//tracing.AddSource("MassTransit");
|
|
||||||
tracing.AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true);
|
|
||||||
tracing.AddNpgsql();
|
|
||||||
})
|
|
||||||
.WithMetrics(metrics =>
|
|
||||||
{
|
|
||||||
metrics.AddRuntimeInstrumentation();
|
|
||||||
metrics.AddProcessInstrumentation();
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Logging.AddOpenTelemetry(logging =>
|
|
||||||
{
|
|
||||||
var resourceBuilder = ResourceBuilder.CreateDefault();
|
|
||||||
resourceBuilderAction(resourceBuilder);
|
|
||||||
logging.SetResourceBuilder(resourceBuilder);
|
|
||||||
logging.IncludeFormattedMessage = true;
|
logging.IncludeFormattedMessage = true;
|
||||||
logging.IncludeScopes = true;
|
logging.IncludeScopes = true;
|
||||||
});
|
});
|
||||||
builder.Services.Configure<OpenTelemetryLoggerOptions>(logging =>
|
});
|
||||||
{
|
|
||||||
logging.AddOtlpExporter(options =>
|
var configuration = builder.Configuration;
|
||||||
{
|
builder.Services.AddOpenTelemetry()
|
||||||
options.Endpoint = new Uri(configuration["OTLP:Logging:Endpoint"] ?? string.Empty);
|
.WithMetrics(metrics => {
|
||||||
});
|
metrics.AddRuntimeInstrumentation().AddProcessInstrumentation().AddMeter("Microsoft.AspNetCore.Hosting", nameof(Continuity.AuthServer))
|
||||||
|
.ConfigureResource(resourceBuilder => resourceBuilder.AddService("Continuity", serviceNamespace: "Wonderking", serviceVersion: "0.0.1"));
|
||||||
|
})
|
||||||
|
.WithTracing(tracing => {
|
||||||
|
if (builder.Environment.IsDevelopment()) {
|
||||||
|
tracing.SetSampler<AlwaysOnSampler>();
|
||||||
|
}
|
||||||
|
tracing.AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true).AddNpgsql();
|
||||||
});
|
});
|
||||||
builder.Services.ConfigureOpenTelemetryMeterProvider(metrics =>
|
|
||||||
{
|
builder.Services.AddMetrics();
|
||||||
metrics.AddOtlpExporter(options =>
|
|
||||||
options.Endpoint = new Uri(configuration["OTLP:Metrics:Endpoint"] ?? string.Empty));
|
builder.Services.Configure<OpenTelemetryLoggerOptions>(logging => logging.AddOtlpExporter());
|
||||||
});
|
builder.Services.ConfigureOpenTelemetryMeterProvider(meter => meter.AddOtlpExporter());
|
||||||
builder.Services.ConfigureOpenTelemetryTracerProvider(tracing =>
|
builder.Services.ConfigureOpenTelemetryTracerProvider(tracer => tracer.AddOtlpExporter());
|
||||||
{
|
|
||||||
tracing.AddZipkinExporter(options =>
|
|
||||||
options.Endpoint = new Uri(configuration["Zipkin:Endpoint"] ?? string.Empty));
|
|
||||||
tracing.AddOtlpExporter(options => options.Endpoint = new Uri(configuration["OTLP:Tracing:Endpoint"] ?? string.Empty));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.Services.AddHealthChecks()
|
builder.Services.AddHealthChecks()
|
||||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
||||||
|
|
||||||
builder.Services.AddDbContextPool<WonderkingContext>(o =>
|
builder.Services.AddDbContextPool<WonderkingContext>(o => {
|
||||||
{
|
|
||||||
o.UseNpgsql(
|
o.UseNpgsql(
|
||||||
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
|
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
|
||||||
.EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory);
|
.EnableSensitiveDataLogging().UseLoggerFactory(loggerFactory);
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddSingleton<CharacterStatsMappingConfiguration>(
|
builder.Services.AddSingleton<CharacterStatsMappingConfiguration>(
|
||||||
|
@ -102,24 +79,33 @@ builder.Services.AddSingleton<CharacterStatsMappingConfiguration>(
|
||||||
File.ReadAllText("config/character-stats.mapping.json")) ?? throw new InvalidOperationException());
|
File.ReadAllText("config/character-stats.mapping.json")) ?? throw new InvalidOperationException());
|
||||||
|
|
||||||
builder.Services.AddSingleton<ILoggerFactory>(loggerFactory);
|
builder.Services.AddSingleton<ILoggerFactory>(loggerFactory);
|
||||||
builder.Services.AddSingleton<PacketDistributorService>();
|
builder.Services.AddSingleton(provider =>
|
||||||
|
new PacketDistributorService<OperationCode, AuthSession>(
|
||||||
|
provider.GetRequiredService<IServiceProvider>(),
|
||||||
|
new List<Assembly> { Assembly.GetAssembly(typeof(OperationCode)) }.AsReadOnly(),
|
||||||
|
new List<Assembly> { Assembly.GetAssembly(typeof(LoginHandler)) }.AsReadOnly()
|
||||||
|
));
|
||||||
builder.Services.AddSingleton<ItemObjectPoolService>();
|
builder.Services.AddSingleton<ItemObjectPoolService>();
|
||||||
builder.Services.AddHostedService(provider =>
|
|
||||||
provider.GetService<ItemObjectPoolService>() ?? throw new InvalidOperationException());
|
|
||||||
builder.Services.AddHostedService(provider =>
|
|
||||||
provider.GetService<PacketDistributorService>() ?? throw new InvalidOperationException());
|
|
||||||
builder.Services.AddMassTransit(x =>
|
|
||||||
{
|
|
||||||
x.UsingInMemory((context, configurator) => configurator.ConfigureEndpoints(context));
|
|
||||||
x.AddMediator(cfg => cfg.AddConsumers(Assembly.GetExecutingAssembly()));
|
|
||||||
});
|
|
||||||
builder.Services.AddHostedService(provider => new WonderkingAuthServer(IPAddress.Any, 10001,
|
builder.Services.AddHostedService(provider => new WonderkingAuthServer(IPAddress.Any, 10001,
|
||||||
provider.GetService<ILogger<WonderkingAuthServer>>() ?? throw new InvalidOperationException(),
|
provider.GetService<ILogger<WonderkingAuthServer>>() ?? throw new InvalidOperationException(),
|
||||||
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException()));
|
provider.GetService<IServiceProvider>() ?? throw new InvalidOperationException()));
|
||||||
|
|
||||||
|
builder.Services.AddHostedService(provider =>
|
||||||
|
provider.GetService<ItemObjectPoolService>() ?? throw new InvalidOperationException());
|
||||||
|
|
||||||
|
builder.Services.AddHostedService(provider =>
|
||||||
|
provider.GetService<PacketDistributorService<OperationCode, AuthSession>>() ??
|
||||||
|
throw new InvalidOperationException());
|
||||||
|
|
||||||
|
builder.Services.AddMassTransit(x => {
|
||||||
|
x.UsingInMemory((context, configurator) => configurator.ConfigureEndpoints(context));
|
||||||
|
x.AddMediator(cfg => cfg.AddConsumers(Assembly.GetExecutingAssembly()));
|
||||||
|
});
|
||||||
|
|
||||||
using var host = builder.Build();
|
using var host = builder.Build();
|
||||||
using (var scope = host.Services.CreateScope())
|
|
||||||
{
|
await using (var scope = host.Services.CreateAsyncScope()) {
|
||||||
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
|
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
|
||||||
await db.Database.MigrateAsync();
|
await db.Database.MigrateAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using Continuity.AuthServer.DB.Documents;
|
using Continuity.AuthServer.DB.Documents;
|
||||||
|
@ -10,14 +10,12 @@ using Wonderking.Game.Reader;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.Services;
|
namespace Continuity.AuthServer.Services;
|
||||||
|
|
||||||
public class ItemObjectPoolService : IHostedService
|
public class ItemObjectPoolService : IHostedService {
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<uint, ItemObject> _itemObjectPool;
|
private readonly ConcurrentDictionary<uint, ItemObject> _itemObjectPool;
|
||||||
private readonly ItemReader _itemReader;
|
private readonly ItemReader _itemReader;
|
||||||
private readonly ILogger<ItemObjectPoolService> _logger;
|
private readonly ILogger<ItemObjectPoolService> _logger;
|
||||||
|
|
||||||
public ItemObjectPoolService(IConfiguration configuration, ILogger<ItemObjectPoolService> logger)
|
public ItemObjectPoolService(IConfiguration configuration, ILogger<ItemObjectPoolService> logger) {
|
||||||
{
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_itemReader = new ItemReader(configuration.GetSection("Game").GetSection("Data").GetValue<string>("Path") ??
|
_itemReader = new ItemReader(configuration.GetSection("Game").GetSection("Data").GetValue<string>("Path") ??
|
||||||
string.Empty);
|
string.Empty);
|
||||||
|
@ -25,58 +23,48 @@ public class ItemObjectPoolService : IHostedService
|
||||||
_itemObjectPool = new ConcurrentDictionary<uint, ItemObject>();
|
_itemObjectPool = new ConcurrentDictionary<uint, ItemObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken) {
|
||||||
{
|
|
||||||
var amountOfEntries = _itemReader.GetAmountOfEntries();
|
var amountOfEntries = _itemReader.GetAmountOfEntries();
|
||||||
Parallel.For(0, (int)amountOfEntries, i =>
|
Parallel.For(0, (int)amountOfEntries, i => {
|
||||||
{
|
|
||||||
var itemObject = _itemReader.GetEntry((uint)i);
|
var itemObject = _itemReader.GetEntry((uint)i);
|
||||||
var result = _itemObjectPool.TryAdd(itemObject.ItemID, itemObject);
|
var result = _itemObjectPool.TryAdd(itemObject.ItemID, itemObject);
|
||||||
if (!result)
|
if (!result) {
|
||||||
{
|
|
||||||
throw new KeyNotFoundException($"Failed to add item {itemObject.ItemID} to the item object pool");
|
throw new KeyNotFoundException($"Failed to add item {itemObject.ItemID} to the item object pool");
|
||||||
}
|
}
|
||||||
|
_logger.LogTrace("Item with id:{ID} and name: '{Name}' has been added", itemObject.ItemID, itemObject.Name);
|
||||||
_logger.LogTrace("Item with {ID} has been added", itemObject.ItemID);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_logger.LogInformation("A total of {AmountOfEntries} items have been added to the item object pool",
|
_logger.LogInformation("A total of {AmountOfEntries} items have been added to the item object pool",
|
||||||
_itemObjectPool.Count);
|
_itemObjectPool.Count);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken) {
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemObject GetItem(ushort itemId)
|
public ItemObject GetItem(ushort itemId) {
|
||||||
{
|
|
||||||
_ = _itemObjectPool.TryGetValue(itemId, out var itemObject);
|
_ = _itemObjectPool.TryGetValue(itemId, out var itemObject);
|
||||||
return itemObject;
|
return itemObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsItem(ushort itemId)
|
public bool ContainsItem(ushort itemId) {
|
||||||
{
|
|
||||||
return _itemObjectPool.ContainsKey(itemId);
|
return _itemObjectPool.ContainsKey(itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQueryable<ItemObject> QueryItems()
|
public IQueryable<ItemObject> QueryItems() {
|
||||||
{
|
|
||||||
return _itemObjectPool.AsReadOnly().Values.AsQueryable();
|
return _itemObjectPool.AsReadOnly().Values.AsQueryable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public InventoryItem GetBaseInventoryItem(ushort itemId, ushort count = 1, bool isWorn = false)
|
public InventoryItem GetBaseInventoryItem(ushort itemId, ushort count = 1, bool isWorn = false) {
|
||||||
{
|
|
||||||
var item = GetItem(itemId);
|
var item = GetItem(itemId);
|
||||||
return new InventoryItem
|
return new InventoryItem {
|
||||||
{
|
|
||||||
ItemId = itemId,
|
ItemId = itemId,
|
||||||
Count = count,
|
Count = count,
|
||||||
Slot = (byte)item.SlotNo1,
|
Slot = (byte)item.SlotNo1,
|
||||||
InventoryTab =
|
InventoryTab =
|
||||||
item.ItemType switch
|
item.ItemType switch {
|
||||||
{
|
|
||||||
1 => InventoryTab.WornCashEquipment,
|
1 => InventoryTab.WornCashEquipment,
|
||||||
2 => isWorn ? InventoryTab.WornEquipment : InventoryTab.Equipment,
|
2 => isWorn ? InventoryTab.WornEquipment : InventoryTab.Equipment,
|
||||||
3 => InventoryTab.Etc,
|
3 => InventoryTab.Etc,
|
||||||
|
|
|
@ -1,187 +0,0 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
|
||||||
using Continuity.AuthServer.LoggerMessages;
|
|
||||||
using Continuity.AuthServer.PacketHandlers;
|
|
||||||
using Continuity.AuthServer.Packets;
|
|
||||||
using DotNext.Collections.Generic;
|
|
||||||
using DotNext.Linq.Expressions;
|
|
||||||
using DotNext.Metaprogramming;
|
|
||||||
using MassTransit.Internals;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.VisualBasic.CompilerServices;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Wonderking.Packets;
|
|
||||||
|
|
||||||
namespace Continuity.AuthServer.Services;
|
|
||||||
|
|
||||||
using static CodeGenerator;
|
|
||||||
using static ExpressionBuilder;
|
|
||||||
|
|
||||||
public class PacketDistributorService : IHostedService, IDisposable
|
|
||||||
{
|
|
||||||
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
|
|
||||||
|
|
||||||
private readonly ILogger<PacketDistributorService> _logger;
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
|
|
||||||
private ImmutableDictionary<OperationCode,
|
|
||||||
Func<byte[], IPacket>> _deserializationMap;
|
|
||||||
|
|
||||||
private ConcurrentDictionary<OperationCode, IPacketHandler> _packetHandlersInstantiation;
|
|
||||||
private readonly ActivitySource _activitySource;
|
|
||||||
|
|
||||||
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
_concurrentQueue = new ConcurrentQueue<RawPacket>();
|
|
||||||
_logger = logger;
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
_activitySource = new ActivitySource(nameof(Server));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var tempDeserializationMap =
|
|
||||||
new Dictionary<OperationCode, Func<byte[], IPacket>>();
|
|
||||||
|
|
||||||
var wonderkingAssembly = Assembly.GetAssembly(typeof(IPacket));
|
|
||||||
var packetsTypes = GetPacketsWithId(wonderkingAssembly);
|
|
||||||
var packetHandlers = GetAllPacketHandlersWithId(Assembly.GetExecutingAssembly());
|
|
||||||
_packetHandlersInstantiation = new ConcurrentDictionary<OperationCode, IPacketHandler>();
|
|
||||||
packetHandlers.ForEach(x =>
|
|
||||||
{
|
|
||||||
var packetHandler =
|
|
||||||
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
|
|
||||||
x.Value);
|
|
||||||
_packetHandlersInstantiation.TryAdd(x.Key, packetHandler as IPacketHandler);
|
|
||||||
});
|
|
||||||
foreach (var packetsType in packetsTypes)
|
|
||||||
{
|
|
||||||
var lambda = Lambda<Func<byte[], IPacket>>(fun =>
|
|
||||||
{
|
|
||||||
var argPacketData = fun[0];
|
|
||||||
var newPacket = packetsType.Value.New();
|
|
||||||
|
|
||||||
var packetVariable = DeclareVariable(packetsType.Value, "packet");
|
|
||||||
Assign(packetVariable, newPacket);
|
|
||||||
Call(packetVariable, nameof(IPacket.Deserialize), argPacketData);
|
|
||||||
|
|
||||||
Return(packetVariable);
|
|
||||||
}).Compile();
|
|
||||||
_logger.PacketCreationFunctionCreated(packetsType.Key);
|
|
||||||
tempDeserializationMap.Add(packetsType.Key, lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
_deserializationMap = tempDeserializationMap.ToImmutableDictionary();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
|
|
||||||
{
|
|
||||||
// ! : We are filtering if types that don't have an instance of the required Attribute
|
|
||||||
var packetsWithId = executingAssembly.GetTypes().AsParallel()
|
|
||||||
.Where(type => type.HasInterface(typeof(IPacket)) && type is { IsInterface: false, IsAbstract: false })
|
|
||||||
.Where(type => type.Namespace?.Contains("Incoming") ?? false)
|
|
||||||
.Select(type => new { Type = type, Attribute = type.GetCustomAttribute<PacketIdAttribute>() })
|
|
||||||
.Where(item => item.Attribute is not null)
|
|
||||||
.ToDictionary(item => item.Attribute!.Code, item => item.Type);
|
|
||||||
if (packetsWithId is not { Count: 0 })
|
|
||||||
{
|
|
||||||
packetsWithId.AsParallel()
|
|
||||||
.ForAll(packet => _logger.PacketWithIdAdded(packet.Key, packet.Value.FullName));
|
|
||||||
return packetsWithId;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.NoPacketsFound();
|
|
||||||
throw new IncompleteInitialization();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
|
|
||||||
{
|
|
||||||
// ! : We are filtering if types that don't have an instance of the required Attribute
|
|
||||||
var packetHandlersWithId = assembly.GetTypes().AsParallel()
|
|
||||||
.Where(t =>
|
|
||||||
t is { IsClass: true, IsAbstract: false } && Array.Exists(t
|
|
||||||
.GetInterfaces(), i =>
|
|
||||||
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>)))
|
|
||||||
.Select(type => new
|
|
||||||
{
|
|
||||||
Type = type,
|
|
||||||
PacketId = type
|
|
||||||
.GetInterfaces().First(t1 =>
|
|
||||||
t1 is { IsGenericType: true } && t1.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
|
|
||||||
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>()?.Code
|
|
||||||
})
|
|
||||||
.Where(x => x.PacketId is not null)
|
|
||||||
.ToDictionary(
|
|
||||||
x => x.PacketId!.Value, x => x.Type
|
|
||||||
);
|
|
||||||
|
|
||||||
if (packetHandlersWithId is not { Count: 0 })
|
|
||||||
{
|
|
||||||
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
|
|
||||||
_logger.PacketHandlerWithIdAdded(packetHandler.Key, packetHandler.Value.FullName));
|
|
||||||
return packetHandlersWithId;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.NoPacketHandlersFound();
|
|
||||||
throw new IncompleteInitialization();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddPacket(RawPacket rawPacket)
|
|
||||||
{
|
|
||||||
_concurrentQueue.Enqueue(rawPacket);
|
|
||||||
DequeueRawPacket();
|
|
||||||
_logger.PacketReceived(rawPacket.OperationCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DequeueRawPacket()
|
|
||||||
{
|
|
||||||
if (_concurrentQueue.TryDequeue(out var item))
|
|
||||||
{
|
|
||||||
ThreadPool.QueueUserWorkItem(InvokePacketHandler, item, preferLocal: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokePacketHandler(RawPacket item)
|
|
||||||
{
|
|
||||||
IPacket packet;
|
|
||||||
_logger.PacketDequeued(item.Session.Id, item.OperationCode);
|
|
||||||
if (!_deserializationMap.TryGetValue(item.OperationCode, out var value))
|
|
||||||
{
|
|
||||||
_logger.PacketTypeNotFound(item.OperationCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var packetParsingActivity = _activitySource.StartActivity("PacketParsing"))
|
|
||||||
{
|
|
||||||
packetParsingActivity?.SetTag("PacketId", item.OperationCode);
|
|
||||||
packet = value(item.MessageBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var packetHandlerActivity = _activitySource.StartActivity("PacketHandler"))
|
|
||||||
{
|
|
||||||
packetHandlerActivity?.SetTag("PacketId", item.OperationCode);
|
|
||||||
_ = _packetHandlersInstantiation[item.OperationCode].TryHandleAsync(packet, item.Session);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.PacketData(JsonConvert.SerializeObject(packet));
|
|
||||||
_logger.PacketFinished(item.Session.Id, item.OperationCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
_activitySource.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
@ -9,74 +9,62 @@ using NetCoreServer;
|
||||||
|
|
||||||
namespace Continuity.AuthServer.Services;
|
namespace Continuity.AuthServer.Services;
|
||||||
|
|
||||||
public class WonderkingAuthServer : TcpServer, IHostedService
|
public class WonderkingAuthServer : TcpServer, IHostedService {
|
||||||
{
|
|
||||||
private readonly ILogger<WonderkingAuthServer> _logger;
|
private readonly ILogger<WonderkingAuthServer> _logger;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
|
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
|
||||||
IServiceProvider serviceProvider) : base(address, port)
|
IServiceProvider serviceProvider) : base(address, port) {
|
||||||
{
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken) {
|
||||||
{
|
|
||||||
Start();
|
Start();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken) {
|
||||||
{
|
|
||||||
DisconnectAll();
|
DisconnectAll();
|
||||||
Stop();
|
Stop();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TcpSession CreateSession()
|
protected override TcpSession CreateSession() {
|
||||||
{
|
|
||||||
return ActivatorUtilities.CreateInstance<AuthSession>(_serviceProvider, this);
|
return ActivatorUtilities.CreateInstance<AuthSession>(_serviceProvider, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStarting()
|
protected override void OnStarting() {
|
||||||
{
|
|
||||||
_logger.LogInformation("Starting");
|
_logger.LogInformation("Starting");
|
||||||
base.OnStarting();
|
base.OnStarting();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStarted()
|
protected override void OnStarted() {
|
||||||
{
|
|
||||||
_logger.LogInformation("Started");
|
_logger.LogInformation("Started");
|
||||||
base.OnStarted();
|
base.OnStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStopping()
|
protected override void OnStopping() {
|
||||||
{
|
|
||||||
_logger.LogInformation("Stopping");
|
_logger.LogInformation("Stopping");
|
||||||
base.OnStopping();
|
base.OnStopping();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStopped()
|
protected override void OnStopped() {
|
||||||
{
|
|
||||||
_logger.LogInformation("Stopped");
|
_logger.LogInformation("Stopped");
|
||||||
base.OnStopped();
|
base.OnStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConnected(TcpSession session)
|
protected override void OnConnected(TcpSession session) {
|
||||||
{
|
|
||||||
_logger.LogInformation("Client connected {Session}", session.Id);
|
_logger.LogInformation("Client connected {Session}", session.Id);
|
||||||
base.OnConnected(session);
|
base.OnConnected(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisconnected(TcpSession session)
|
protected override void OnDisconnected(TcpSession session) {
|
||||||
{
|
|
||||||
_logger.LogInformation("Client disconnected {Session}", session.Id);
|
_logger.LogInformation("Client disconnected {Session}", session.Id);
|
||||||
base.OnDisconnected(session);
|
base.OnDisconnected(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnError(SocketError error)
|
protected override void OnError(SocketError error) {
|
||||||
{
|
|
||||||
_logger.LogError("An error has occured {Error}", error);
|
_logger.LogError("An error has occured {Error}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
Continuity.WorldServer/Continuity.WorldServer.csproj
Normal file
21
Continuity.WorldServer/Continuity.WorldServer.csproj
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Wonderking\Wonderking.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
21
Continuity.WorldServer/Program.cs
Normal file
21
Continuity.WorldServer/Program.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
Span<byte> buffer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
||||||
|
Console.WriteLine(buffer.Length == Marshal.SizeOf<TestStruct>());
|
||||||
|
var tstruct = MemoryMarshal.Cast<byte, TestStruct>(buffer)[0];
|
||||||
|
Console.WriteLine(JsonSerializer.Serialize(tstruct));
|
||||||
|
Console.WriteLine(tstruct.b);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 20)]
|
||||||
|
public struct TestStruct {
|
||||||
|
[FieldOffset(0)]
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 4)]
|
||||||
|
public int[] arr;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int b;
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Continuity.AuthServer", "Continuity.AuthServer\Continuity.AuthServer.csproj", "{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wonderking", "Wonderking\Wonderking.csproj", "{6B53A10B-C397-4347-BB00-A12272D0528E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
6
Continuity.slnx
Normal file
6
Continuity.slnx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<Solution>
|
||||||
|
<Project Path="Benchmarks/Benchmarks.csproj" />
|
||||||
|
<Project Path="Continuity.AuthServer/Continuity.AuthServer.csproj" />
|
||||||
|
<Project Path="Continuity.WorldServer/Continuity.WorldServer.csproj" />
|
||||||
|
<Project Path="Wonderking/Wonderking.csproj" />
|
||||||
|
</Solution>
|
|
@ -4,3 +4,11 @@ This is a continuation and rewrite of the original Project Infinity for Wonderki
|
||||||
## Important notes for developers
|
## Important notes for developers
|
||||||
|
|
||||||
* Avoid using statements with TcpSession, AuthSession or any type that inherits Session outside the session itself.
|
* Avoid using statements with TcpSession, AuthSession or any type that inherits Session outside the session itself.
|
||||||
|
|
||||||
|
# Scripts example usage
|
||||||
|
|
||||||
|
**split_dat_file.ps1**
|
||||||
|
``.\scripts\split_dat_file.ps1 .\wk-data\baseitemdata_clean.dat 932 9``
|
||||||
|
|
||||||
|
**dexor_binary_file.ps1**
|
||||||
|
``.\scripts\dexor_binary_file.ps1 .\wk-data\baseitemdata.dat .\wk-data\baseitemdata_clean.dat 0xc5``
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Character;
|
namespace Wonderking.Game.Data.Character;
|
||||||
|
|
||||||
public enum Gender : byte
|
public enum Gender : byte {
|
||||||
{
|
|
||||||
None = 0,
|
None = 0,
|
||||||
Male = 1,
|
Male = 1,
|
||||||
Female = 2
|
Female = 2
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Character;
|
namespace Wonderking.Game.Data.Character;
|
||||||
|
|
||||||
public enum PvPLevel : byte
|
public enum PvPLevel : byte {
|
||||||
{
|
|
||||||
None = 0,
|
None = 0,
|
||||||
Dualer = 1,
|
Dualer = 1,
|
||||||
Challenger = 2,
|
Challenger = 2,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Item;
|
namespace Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
public struct ContainedItem
|
public struct ContainedItem {
|
||||||
{
|
|
||||||
public short ID { get; internal set; }
|
public short ID { get; internal set; }
|
||||||
public float ObtainChance { get; internal set; }
|
public float ObtainChance { get; internal set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Item;
|
namespace Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct CraftMaterial
|
public struct CraftMaterial {
|
||||||
{
|
|
||||||
public uint ID;
|
public uint ID;
|
||||||
public uint Amount;
|
public uint Amount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Item;
|
namespace Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||||
public struct ElementalStats
|
public struct ElementalStats {
|
||||||
{
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
[MarshalAs(UnmanagedType.I4)]
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
public int MinimumFireDamage;
|
public int MinimumFireDamage;
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Item;
|
namespace Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
public struct ItemOptions
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
{
|
public struct ItemOptions {
|
||||||
public uint[] OptionIDs { get; internal set; }
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
|
||||||
public bool OptionAvailable { get; internal set; }
|
public uint[] OptionIDs;
|
||||||
|
|
||||||
|
public bool OptionAvailable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Data.Item;
|
namespace Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
||||||
public struct Stats
|
public struct Stats {
|
||||||
{
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
[MarshalAs(UnmanagedType.I4)]
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
public int Strength;
|
public int Strength;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Wonderking.Game.Data.Item;
|
using Wonderking.Game.Data.Item;
|
||||||
|
@ -7,8 +7,7 @@ using Wonderking.Utils;
|
||||||
namespace Wonderking.Game.Data;
|
namespace Wonderking.Game.Data;
|
||||||
|
|
||||||
[GameDataMetadata(932, "baseitemdata.dat", 197)]
|
[GameDataMetadata(932, "baseitemdata.dat", 197)]
|
||||||
public struct ItemObject
|
public struct ItemObject {
|
||||||
{
|
|
||||||
public uint ItemID { get; set; }
|
public uint ItemID { get; set; }
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
public uint ItemType { get; set; }
|
public uint ItemType { get; set; }
|
||||||
|
@ -128,10 +127,10 @@ public struct ItemObject
|
||||||
[JsonConverter(typeof(ByteArrayConverter))]
|
[JsonConverter(typeof(ByteArrayConverter))]
|
||||||
public byte[] R16C { get; set; }
|
public byte[] R16C { get; set; }
|
||||||
|
|
||||||
public int InventoryX { get; set; }
|
public int SheetX { get; set; }
|
||||||
public int InventoryY { get; set; }
|
public int SheetY { get; set; }
|
||||||
public int InventoryWidth { get; set; }
|
public int SheetWidth { get; set; }
|
||||||
public int InventoryHeight { get; set; }
|
public int SheetHeight { get; set; }
|
||||||
public int SheetID { get; set; }
|
public int SheetID { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
@ -169,4 +168,7 @@ public struct ItemObject
|
||||||
|
|
||||||
[JsonConverter(typeof(ByteArrayConverter))]
|
[JsonConverter(typeof(ByteArrayConverter))]
|
||||||
public byte[] Unknown21_2 { get; set; }
|
public byte[] Unknown21_2 { get; set; }
|
||||||
|
|
||||||
|
public int RearWearItemIndex { get; set; }
|
||||||
|
public int FrontWearItemIndex { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Wonderking.Game;
|
namespace Wonderking.Game;
|
||||||
|
|
||||||
public abstract class DataReader<T>
|
public abstract class DataReader<T> {
|
||||||
{
|
|
||||||
private readonly string _datFileName;
|
private readonly string _datFileName;
|
||||||
|
|
||||||
private readonly byte _xorKey;
|
private readonly byte _xorKey;
|
||||||
protected readonly ushort SizeOfEntry;
|
protected readonly ushort SizeOfEntry;
|
||||||
|
|
||||||
protected DataReader(string path)
|
protected DataReader(string path) {
|
||||||
{
|
|
||||||
Path = path;
|
Path = path;
|
||||||
_xorKey = GetXorKey();
|
_xorKey = GetXorKey();
|
||||||
SizeOfEntry = GetSizeOfEntry();
|
SizeOfEntry = GetSizeOfEntry();
|
||||||
|
@ -27,31 +25,26 @@ public abstract class DataReader<T>
|
||||||
public abstract uint GetAmountOfEntries();
|
public abstract uint GetAmountOfEntries();
|
||||||
public abstract T GetEntry(uint entryId);
|
public abstract T GetEntry(uint entryId);
|
||||||
|
|
||||||
private static ushort GetSizeOfEntry()
|
private static ushort GetSizeOfEntry() {
|
||||||
{
|
|
||||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DataEntrySize ??
|
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DataEntrySize ??
|
||||||
throw new NotSupportedException("DataEntrySize is null");
|
throw new NotSupportedException("DataEntrySize is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDatFileName()
|
private static string GetDatFileName() {
|
||||||
{
|
|
||||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DatFileName ??
|
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DatFileName ??
|
||||||
throw new NotSupportedException("DatFileName is null");
|
throw new NotSupportedException("DatFileName is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte GetXorKey()
|
private static byte GetXorKey() {
|
||||||
{
|
|
||||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.XorKey ??
|
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.XorKey ??
|
||||||
throw new NotSupportedException("XorKey is null");
|
throw new NotSupportedException("XorKey is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Span<byte> GetDatFileContent(string path)
|
private ReadOnlySpan<byte> GetDatFileContent(string path) {
|
||||||
{
|
|
||||||
var fileData = File.ReadAllBytes(path + _datFileName);
|
var fileData = File.ReadAllBytes(path + _datFileName);
|
||||||
var data = new byte[fileData.Length];
|
var data = new byte[fileData.Length];
|
||||||
|
|
||||||
for (var i = 0; i < fileData.Length; i++)
|
for (var i = 0; i < fileData.Length; i++) {
|
||||||
{
|
|
||||||
data[i] = (byte)(fileData[i] ^ _xorKey);
|
data[i] = (byte)(fileData[i] ^ _xorKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Wonderking.Game;
|
namespace Wonderking.Game;
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
|
||||||
public class GameDataMetadataAttribute(ushort dataEntrySize, string datFileName, byte xorKey) : Attribute
|
public class GameDataMetadataAttribute(ushort dataEntrySize, string datFileName, byte xorKey) : Attribute {
|
||||||
{
|
|
||||||
[UsedImplicitly] public byte XorKey { get; init; } = xorKey;
|
[UsedImplicitly] public byte XorKey { get; init; } = xorKey;
|
||||||
[UsedImplicitly] public ushort DataEntrySize { get; init; } = dataEntrySize;
|
[UsedImplicitly] public ushort DataEntrySize { get; init; } = dataEntrySize;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Wonderking.Game.Mapping;
|
namespace Wonderking.Game.Mapping;
|
||||||
|
|
||||||
public class CharacterStatsMappingConfiguration
|
public class CharacterStatsMappingConfiguration {
|
||||||
{
|
|
||||||
[JsonPropertyName("default")] public required DefaultCharacterMapping DefaultCharacterMapping { get; set; }
|
[JsonPropertyName("default")] public required DefaultCharacterMapping DefaultCharacterMapping { get; set; }
|
||||||
[JsonPropertyName("1")] public required JobSpecificMapping Swordsman { get; set; }
|
[JsonPropertyName("1")] public required JobSpecificMapping Swordsman { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Wonderking.Game.Mapping;
|
namespace Wonderking.Game.Mapping;
|
||||||
|
|
||||||
public class DefaultCharacterMapping
|
public class DefaultCharacterMapping {
|
||||||
{
|
|
||||||
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Wonderking.Game.Mapping;
|
namespace Wonderking.Game.Mapping;
|
||||||
|
|
||||||
public class DynamicStats
|
public class DynamicStats {
|
||||||
{
|
|
||||||
[JsonPropertyName("healthPerLevel")] public int HealthPerLevel { get; set; }
|
[JsonPropertyName("healthPerLevel")] public int HealthPerLevel { get; set; }
|
||||||
[JsonPropertyName("manaPerLevel")] public int ManaPerLevel { get; set; }
|
[JsonPropertyName("manaPerLevel")] public int ManaPerLevel { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Wonderking.Game.Mapping;
|
namespace Wonderking.Game.Mapping;
|
||||||
|
|
||||||
public class Item
|
public class Item {
|
||||||
{
|
|
||||||
[JsonPropertyName("id")] public ushort Id { get; set; }
|
[JsonPropertyName("id")] public ushort Id { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("quantity")] public ushort Quantity { get; set; }
|
[JsonPropertyName("quantity")] public ushort Quantity { get; set; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
@ -7,8 +7,7 @@ using Wonderking.Packets.Outgoing.Data;
|
||||||
namespace Wonderking.Game.Mapping;
|
namespace Wonderking.Game.Mapping;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class JobSpecificMapping
|
public class JobSpecificMapping {
|
||||||
{
|
|
||||||
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("baseStats")] public required BaseStats BaseStats { get; set; }
|
[JsonPropertyName("baseStats")] public required BaseStats BaseStats { get; set; }
|
||||||
|
|
|
@ -1,75 +1,61 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Game.Reader;
|
namespace Wonderking.Game.Reader;
|
||||||
|
|
||||||
public static class BinaryReader<T> where T : new()
|
public static class BinaryReader<T> where T : new() {
|
||||||
{
|
|
||||||
public static readonly Func<BinaryReader, T> Read;
|
public static readonly Func<BinaryReader, T> Read;
|
||||||
|
|
||||||
|
#pragma warning disable MA0051, CA1810
|
||||||
static BinaryReader()
|
static BinaryReader()
|
||||||
|
#pragma warning restore MA0051, CA1810
|
||||||
{
|
{
|
||||||
var type = typeof(T);
|
var type = typeof(T);
|
||||||
|
|
||||||
if (type == typeof(bool))
|
if (type == typeof(bool)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, bool>)(p => p.ReadBoolean());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, bool>)(p => p.ReadBoolean());
|
||||||
}
|
}
|
||||||
else if (type == typeof(char))
|
else if (type == typeof(char)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, char>)(p => p.ReadChar());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, char>)(p => p.ReadChar());
|
||||||
}
|
}
|
||||||
else if (type == typeof(string))
|
else if (type == typeof(string)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, string>)(p => p.ReadString());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, string>)(p => p.ReadString());
|
||||||
}
|
}
|
||||||
else if (type == typeof(sbyte))
|
else if (type == typeof(sbyte)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, sbyte>)(p => p.ReadSByte());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, sbyte>)(p => p.ReadSByte());
|
||||||
}
|
}
|
||||||
else if (type == typeof(short))
|
else if (type == typeof(short)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, short>)(p => p.ReadInt16());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, short>)(p => p.ReadInt16());
|
||||||
}
|
}
|
||||||
else if (type == typeof(int))
|
else if (type == typeof(int)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, int>)(p => p.ReadInt32());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, int>)(p => p.ReadInt32());
|
||||||
}
|
}
|
||||||
else if (type == typeof(long))
|
else if (type == typeof(long)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, long>)(p => p.ReadInt64());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, long>)(p => p.ReadInt64());
|
||||||
}
|
}
|
||||||
else if (type == typeof(byte))
|
else if (type == typeof(byte)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, byte>)(p => p.ReadByte());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, byte>)(p => p.ReadByte());
|
||||||
}
|
}
|
||||||
else if (type == typeof(ushort))
|
else if (type == typeof(ushort)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ushort>)(p => p.ReadUInt16());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ushort>)(p => p.ReadUInt16());
|
||||||
}
|
}
|
||||||
else if (type == typeof(uint))
|
else if (type == typeof(uint)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, uint>)(p => p.ReadUInt32());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, uint>)(p => p.ReadUInt32());
|
||||||
}
|
}
|
||||||
else if (type == typeof(ulong))
|
else if (type == typeof(ulong)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ulong>)(p => p.ReadUInt64());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ulong>)(p => p.ReadUInt64());
|
||||||
}
|
}
|
||||||
else if (type == typeof(float))
|
else if (type == typeof(float)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, float>)(p => p.ReadSingle());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, float>)(p => p.ReadSingle());
|
||||||
}
|
}
|
||||||
else if (type == typeof(double))
|
else if (type == typeof(double)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, double>)(p => p.ReadDouble());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, double>)(p => p.ReadDouble());
|
||||||
}
|
}
|
||||||
else if (type == typeof(decimal))
|
else if (type == typeof(decimal)) {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, decimal>)(p => p.ReadDecimal());
|
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, decimal>)(p => p.ReadDecimal());
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
Read = (Func<BinaryReader, T>)(p =>
|
Read = (Func<BinaryReader, T>)(p =>
|
||||||
(T)(object)p.ReadBytes(Marshal.SizeOf(new T())));
|
(T)(object)p.ReadBytes(Marshal.SizeOf(new T())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,25 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
/* Nicht gemergte Änderung aus Projekt "Wonderking(net7.0)"
|
|
||||||
Vor:
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
Nach:
|
|
||||||
using System.Text;
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Wonderking.Game.Reader;
|
namespace Wonderking.Game.Reader;
|
||||||
|
|
||||||
public static class GenericReaderExtensions
|
public static class GenericReaderExtensions {
|
||||||
{
|
public static string ReadString(this BinaryReader reader, int length) {
|
||||||
public static string ReadString(this BinaryReader reader, int length)
|
var ret = Encoding.ASCII.GetString(reader.ReadBytes(length)).Replace("\0", "", StringComparison.Ordinal);
|
||||||
{
|
|
||||||
var ret = Encoding.ASCII.GetString(reader.ReadBytes(length)).Replace("\0", "");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T[] ReadArray<T>(this BinaryReader pReader, int pLength) where T : new()
|
public static T[] ReadArray<T>(this BinaryReader pReader, int pLength) where T : new() {
|
||||||
{
|
|
||||||
var array = new T[pLength];
|
var array = new T[pLength];
|
||||||
for (var index = 0; index < pLength; ++index)
|
for (var index = 0; index < pLength; ++index) {
|
||||||
{
|
|
||||||
array[index] = pReader.Read<T>();
|
array[index] = pReader.Read<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Read<T>(this BinaryReader br) where T : new()
|
public static T Read<T>(this BinaryReader br) where T : new() {
|
||||||
{
|
|
||||||
return BinaryReader<T>.Read(br);
|
return BinaryReader<T>.Read(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Wonderking.Game.Data;
|
using Wonderking.Game.Data;
|
||||||
using Wonderking.Game.Data.Item;
|
using Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
namespace Wonderking.Game.Reader;
|
namespace Wonderking.Game.Reader;
|
||||||
|
|
||||||
public class ItemReader(string path) : DataReader<ItemObject>(path)
|
public class ItemReader(string path) : DataReader<ItemObject>(path) {
|
||||||
{
|
public override uint GetAmountOfEntries() {
|
||||||
public override uint GetAmountOfEntries()
|
|
||||||
{
|
|
||||||
return (uint)((DatFileContent.Length - 9) / SizeOfEntry);
|
return (uint)((DatFileContent.Length - 9) / SizeOfEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,34 +46,8 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
||||||
item.Unknown8 = data.Slice(92, 4).ToArray(); // 92 -> 96
|
item.Unknown8 = data.Slice(92, 4).ToArray(); // 92 -> 96
|
||||||
item.R2C = data.Slice(96, 16).ToArray(); // 96 -> 112
|
item.R2C = data.Slice(96, 16).ToArray(); // 96 -> 112
|
||||||
item.Unknown9 = data.Slice(112, 4).ToArray(); // 112 -> 116
|
item.Unknown9 = data.Slice(112, 4).ToArray(); // 112 -> 116
|
||||||
item.Stats = new Stats
|
item.Stats = ReadStats(ref data); // 116 -> 140
|
||||||
{
|
item.ElementalStats = ReadElementalStats(ref data); // 140 -> 204
|
||||||
Strength = BitConverter.ToInt32(data.Slice(116, 4)), // 116 -> 120
|
|
||||||
Dexterity = BitConverter.ToInt32(data.Slice(120, 4)), // 120 -> 124
|
|
||||||
Intelligence = BitConverter.ToInt32(data.Slice(124, 4)), // 124 -> 128
|
|
||||||
Vitality = BitConverter.ToInt32(data.Slice(128, 4)), // 128 -> 132
|
|
||||||
Luck = BitConverter.ToInt32(data.Slice(132, 4)), // 132 -> 136
|
|
||||||
Wisdom = BitConverter.ToInt32(data.Slice(136, 4)) // 136 -> 140
|
|
||||||
}; // 116 -> 140
|
|
||||||
item.ElementalStats = new ElementalStats
|
|
||||||
{
|
|
||||||
MinimumFireDamage = BitConverter.ToInt32(data.Slice(140, 4)), // 140 -> 144
|
|
||||||
MinimumWaterDamage = BitConverter.ToInt32(data.Slice(144, 4)), // 144 -> 148
|
|
||||||
MinimumDarkDamage = BitConverter.ToInt32(data.Slice(148, 4)), // 148 -> 152
|
|
||||||
MinimumHolyDamage = BitConverter.ToInt32(data.Slice(152, 4)), // 152 -> 156
|
|
||||||
MaximumFireDamage = BitConverter.ToInt32(data.Slice(156, 4)), // 156 -> 160
|
|
||||||
MaximumWaterDamage = BitConverter.ToInt32(data.Slice(160, 4)), // 160 -> 164
|
|
||||||
MaximumDarkDamage = BitConverter.ToInt32(data.Slice(164, 4)), // 164 -> 168
|
|
||||||
MaximumHolyDamage = BitConverter.ToInt32(data.Slice(168, 4)), // 168 -> 172
|
|
||||||
ElementFire = BitConverter.ToUInt32(data.Slice(172, 4)), // 172 -> 176
|
|
||||||
ElementWater = BitConverter.ToUInt32(data.Slice(176, 4)), // 176 -> 180
|
|
||||||
ElementDark = BitConverter.ToUInt32(data.Slice(180, 4)), // 180 -> 184
|
|
||||||
ElementHoly = BitConverter.ToUInt32(data.Slice(184, 4)), // 184 -> 188
|
|
||||||
FireResistance = BitConverter.ToInt32(data.Slice(188, 4)), // 188 -> 192
|
|
||||||
WaterResistance = BitConverter.ToInt32(data.Slice(192, 4)), // 192 -> 196
|
|
||||||
DarkResistance = BitConverter.ToInt32(data.Slice(196, 4)), // 196 -> 200
|
|
||||||
HolyResistance = BitConverter.ToInt32(data.Slice(200, 4)) // 200 -> 204
|
|
||||||
}; // 140 -> 204
|
|
||||||
item.R7C = data.Slice(204, 4).ToArray(); // 204 -> 208
|
item.R7C = data.Slice(204, 4).ToArray(); // 204 -> 208
|
||||||
item.R8C = data.Slice(208, 8).ToArray(); // 208 -> 216
|
item.R8C = data.Slice(208, 8).ToArray(); // 208 -> 216
|
||||||
item.Speed = BinaryPrimitives.ReadSingleLittleEndian(data.Slice(216, 4)); // 216 -> 220
|
item.Speed = BinaryPrimitives.ReadSingleLittleEndian(data.Slice(216, 4)); // 216 -> 220
|
||||||
|
@ -101,71 +75,80 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
||||||
item.MinimalAttackDamage = BitConverter.ToInt32(data.Slice(308, 4)); // 308 -> 312
|
item.MinimalAttackDamage = BitConverter.ToInt32(data.Slice(308, 4)); // 308 -> 312
|
||||||
item.MaximalAttackDamage = BitConverter.ToInt32(data.Slice(312, 4)); // 312 -> 316
|
item.MaximalAttackDamage = BitConverter.ToInt32(data.Slice(312, 4)); // 312 -> 316
|
||||||
item.PhysicalDamage = BitConverter.ToInt32(data.Slice(316, 4)); // 316 -> 320
|
item.PhysicalDamage = BitConverter.ToInt32(data.Slice(316, 4)); // 316 -> 320
|
||||||
item.CraftMaterial = new CraftMaterial[]
|
item.CraftMaterial = ReadCraftMaterial(ref data); // 320 -> 352
|
||||||
{
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
ID = BitConverter.ToUInt32(data.Slice(320, 4)), // 320 -> 324
|
|
||||||
Amount = BitConverter.ToUInt32(data.Slice(336, 4)) // 336 -> 340
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
ID = BitConverter.ToUInt32(data.Slice(324, 4)), // 324 -> 328
|
|
||||||
Amount = BitConverter.ToUInt32(data.Slice(340, 4)) // 340 -> 344
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
ID = BitConverter.ToUInt32(data.Slice(328, 4)), // 328 -> 332
|
|
||||||
Amount = BitConverter.ToUInt32(data.Slice(344, 4)) // 344 -> 348
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
ID = BitConverter.ToUInt32(data.Slice(332, 4)), // 332 -> 336
|
|
||||||
Amount = BitConverter.ToUInt32(data.Slice(348, 4)) // 348 -> 352
|
|
||||||
}
|
|
||||||
}; // 320 -> 352
|
|
||||||
item.CraftResultAmount = BitConverter.ToUInt32(data.Slice(352, 4)); // 352 -> 356
|
item.CraftResultAmount = BitConverter.ToUInt32(data.Slice(352, 4)); // 352 -> 356
|
||||||
item.R14C = data.Slice(356, 4).ToArray(); // 356 -> 360
|
item.R14C = data.Slice(356, 4).ToArray(); // 356 -> 360
|
||||||
item.CraftResultItem = BitConverter.ToUInt32(data.Slice(360, 4)); // 360 -> 364
|
item.CraftResultItem = BitConverter.ToUInt32(data.Slice(360, 4)); // 360 -> 364
|
||||||
item.R15C = data.Slice(364, 4).ToArray(); // 364 -> 368
|
item.R15C = data.Slice(364, 4).ToArray(); // 364 -> 368
|
||||||
item.R16C = data.Slice(368, 20).ToArray(); // 368 -> 388
|
item.R16C = data.Slice(368, 12).ToArray(); // 368 -> 380
|
||||||
item.InventoryX = BitConverter.ToInt32(data.Slice(388, 4)); // 388 -> 392
|
item.FrontWearItemIndex = BitConverter.ToInt32(data.Slice(380, 4));
|
||||||
item.InventoryY = BitConverter.ToInt32(data.Slice(392, 4)); // 392 -> 396
|
item.RearWearItemIndex = BitConverter.ToInt32(data.Slice(380, 4));
|
||||||
item.InventoryWidth = BitConverter.ToInt32(data.Slice(396, 4)); // 396 -> 400
|
item.SheetX = BitConverter.ToInt32(data.Slice(388, 4)); // 388 -> 392
|
||||||
item.InventoryHeight = BitConverter.ToInt32(data.Slice(400, 4)); // 400 -> 404
|
item.SheetY = BitConverter.ToInt32(data.Slice(392, 4)); // 392 -> 396
|
||||||
|
item.SheetWidth = BitConverter.ToInt32(data.Slice(396, 4)); // 396 -> 400
|
||||||
|
item.SheetHeight = BitConverter.ToInt32(data.Slice(400, 4)); // 400 -> 404
|
||||||
item.SheetID = BitConverter.ToInt32(data.Slice(404, 4)); // 404 -> 408
|
item.SheetID = BitConverter.ToInt32(data.Slice(404, 4)); // 404 -> 408
|
||||||
item.Name = Encoding.ASCII.GetString(data.Slice(408, 20)); // 408 -> 428
|
item.Name = Encoding.ASCII.GetString(data.Slice(408, 20)); // 408 -> 428
|
||||||
item.Description = Encoding.ASCII.GetString(data.Slice(428, 85)); // 428 -> 513
|
item.Description = Encoding.ASCII.GetString(data.Slice(428, 85)); // 428 -> 513
|
||||||
item.Unknown1 = data.Slice(513, 175).ToArray(); // 513 -> 688
|
item.Unknown1 = data.Slice(513, 175).ToArray(); // 513 -> 688
|
||||||
item.IsEnchantable = BitConverter.ToBoolean(data.Slice(688, 4)); // 688 -> 672
|
item.IsEnchantable = BitConverter.ToBoolean(data.Slice(688, 4)); // 688 -> 672
|
||||||
item.Unknown1_2 = data.Slice(692, 104).ToArray(); // 692 -> 796
|
item.Unknown1_2 = data.Slice(692, 104).ToArray(); // 692 -> 796
|
||||||
item.SetItems = new[]
|
item.SetItems = ReadSetItems(ref data); // 796 -> 816
|
||||||
{
|
|
||||||
BitConverter.ToUInt32(data.Slice(796, 4)), // 796 -> 800
|
|
||||||
BitConverter.ToUInt32(data.Slice(800, 4)), // 800 -> 804
|
|
||||||
BitConverter.ToUInt32(data.Slice(804, 4)), // 804 -> 808
|
|
||||||
BitConverter.ToUInt32(data.Slice(808, 4)), // 808 -> 812
|
|
||||||
BitConverter.ToUInt32(data.Slice(812, 4)) // 812 -> 816
|
|
||||||
}; // 796 -> 816
|
|
||||||
item.SetID = BitConverter.ToUInt32(data.Slice(816, 4)); // 816 -> 820
|
item.SetID = BitConverter.ToUInt32(data.Slice(816, 4)); // 816 -> 820
|
||||||
item.Options = new ItemOptions
|
item.Options = ReadItemOptions(ref data); // 820 -> 840
|
||||||
{
|
|
||||||
OptionIDs = new[]
|
|
||||||
{
|
|
||||||
BitConverter.ToUInt32(data.Slice(824, 4)), // 824 -> 828
|
|
||||||
BitConverter.ToUInt32(data.Slice(828, 4)), // 828 -> 832
|
|
||||||
BitConverter.ToUInt32(data.Slice(832, 4)), // 832 -> 836
|
|
||||||
BitConverter.ToUInt32(data.Slice(836, 4)) // 836 -> 840
|
|
||||||
},
|
|
||||||
OptionAvailable = BitConverter.ToBoolean(data.Slice(820, 4)) // 820 -> 824
|
|
||||||
}; // 820 -> 840
|
|
||||||
item.Unknown19 = data.Slice(840, 23).ToArray(); // 840 -> 863
|
item.Unknown19 = data.Slice(840, 23).ToArray(); // 840 -> 863
|
||||||
item.PetID = data[863]; // 863 -> 864
|
item.PetID = data[863]; // 863 -> 864
|
||||||
item.Unknown20 = data.Slice(864, 20).ToArray(); // 864 -> 884
|
item.Unknown20 = data.Slice(864, 20).ToArray(); // 864 -> 884
|
||||||
item.HitBoxScaling = data[884]; // 884 -> 885
|
item.HitBoxScaling = data[884]; // 884 -> 885
|
||||||
item.Unknown20_2 = data.Slice(885, 13).ToArray(); // 885 -> 898
|
item.Unknown20_2 = data.Slice(885, 13).ToArray(); // 885 -> 898
|
||||||
item.ContainedItems = new[]
|
item.ContainedItems = ReadContainedItems(ref data); // 898 -> 928
|
||||||
{
|
item.MinimumLevelRequirement = data[928]; // 928 -> 929
|
||||||
|
item.Unknown21_2 = data.Slice(929, 3).ToArray(); // 929 -> 932
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static Stats ReadStats(ref Span<byte> data) {
|
||||||
|
return new Stats {
|
||||||
|
Strength = BitConverter.ToInt32(data.Slice(116, 4)), // 116 -> 120
|
||||||
|
Dexterity = BitConverter.ToInt32(data.Slice(120, 4)), // 120 -> 124
|
||||||
|
Intelligence = BitConverter.ToInt32(data.Slice(124, 4)), // 124 -> 128
|
||||||
|
Vitality = BitConverter.ToInt32(data.Slice(128, 4)), // 128 -> 132
|
||||||
|
Luck = BitConverter.ToInt32(data.Slice(132, 4)), // 132 -> 136
|
||||||
|
Wisdom = BitConverter.ToInt32(data.Slice(136, 4)) // 136 -> 140
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint[] ReadSetItems(ref Span<byte> data) {
|
||||||
|
return
|
||||||
|
[
|
||||||
|
BitConverter.ToUInt32(data.Slice(796, 4)), // 796 -> 800
|
||||||
|
BitConverter.ToUInt32(data.Slice(800, 4)), // 800 -> 804
|
||||||
|
BitConverter.ToUInt32(data.Slice(804, 4)), // 804 -> 808
|
||||||
|
BitConverter.ToUInt32(data.Slice(808, 4)), // 808 -> 812
|
||||||
|
BitConverter.ToUInt32(data.Slice(812, 4)) // 812 -> 816
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ItemOptions ReadItemOptions(ref Span<byte> data) {
|
||||||
|
return new ItemOptions {
|
||||||
|
OptionAvailable = BitConverter.ToBoolean(data.Slice(820, 4)), // 820 -> 824
|
||||||
|
OptionIDs =
|
||||||
|
[
|
||||||
|
BitConverter.ToUInt32(data.Slice(824, 4)), // 824 -> 828
|
||||||
|
BitConverter.ToUInt32(data.Slice(828, 4)), // 828 -> 832
|
||||||
|
BitConverter.ToUInt32(data.Slice(832, 4)), // 832 -> 836
|
||||||
|
BitConverter.ToUInt32(data.Slice(836, 4)) // 836 -> 840
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ContainedItem[] ReadContainedItems(ref Span<byte> data) {
|
||||||
|
return
|
||||||
|
[
|
||||||
new ContainedItem
|
new ContainedItem
|
||||||
{
|
{
|
||||||
ID = BitConverter.ToInt16(data.Slice(898, 2)), // 898 -> 900
|
ID = BitConverter.ToInt16(data.Slice(898, 2)), // 898 -> 900
|
||||||
|
@ -191,9 +174,38 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
||||||
ID = BitConverter.ToInt16(data.Slice(906, 2)), // 906 -> 908
|
ID = BitConverter.ToInt16(data.Slice(906, 2)), // 906 -> 908
|
||||||
ObtainChance = BitConverter.ToSingle(data.Slice(924, 4)) // 924 -> 928
|
ObtainChance = BitConverter.ToSingle(data.Slice(924, 4)) // 924 -> 928
|
||||||
}
|
}
|
||||||
};
|
];
|
||||||
item.MinimumLevelRequirement = data[928]; // 928 -> 929
|
}
|
||||||
item.Unknown21_2 = data.Slice(929, 3).ToArray(); // 929 -> 932
|
|
||||||
return item;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static CraftMaterial[] ReadCraftMaterial(ref Span<byte> data) {
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new CraftMaterial
|
||||||
|
{
|
||||||
|
ID = BitConverter.ToUInt32(data.Slice(320, 4)), // 320 -> 324
|
||||||
|
Amount = BitConverter.ToUInt32(data.Slice(336, 4)) // 336 -> 340
|
||||||
|
},
|
||||||
|
new CraftMaterial
|
||||||
|
{
|
||||||
|
ID = BitConverter.ToUInt32(data.Slice(324, 4)), // 324 -> 328
|
||||||
|
Amount = BitConverter.ToUInt32(data.Slice(340, 4)) // 340 -> 344
|
||||||
|
},
|
||||||
|
new CraftMaterial
|
||||||
|
{
|
||||||
|
ID = BitConverter.ToUInt32(data.Slice(328, 4)), // 328 -> 332
|
||||||
|
Amount = BitConverter.ToUInt32(data.Slice(344, 4)) // 344 -> 348
|
||||||
|
},
|
||||||
|
new CraftMaterial
|
||||||
|
{
|
||||||
|
ID = BitConverter.ToUInt32(data.Slice(332, 4)), // 332 -> 336
|
||||||
|
Amount = BitConverter.ToUInt32(data.Slice(348, 4)) // 348 -> 352
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static ElementalStats ReadElementalStats(ref Span<byte> data) {
|
||||||
|
return MemoryMarshal.Cast<byte, ElementalStats>(data.Slice(140, 64))[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Wonderking.Game.Data.Item;
|
using Wonderking.Game.Data.Item;
|
||||||
|
|
||||||
namespace Wonderking.Game.Reader;
|
namespace Wonderking.Game.Reader;
|
||||||
|
|
||||||
public static class ItemReaderExtensions
|
public static class ItemReaderExtensions {
|
||||||
{
|
public static Stats ReadStats(this BinaryReader reader) {
|
||||||
public static Stats ReadStats(this BinaryReader reader)
|
return new Stats {
|
||||||
{
|
|
||||||
return new Stats
|
|
||||||
{
|
|
||||||
Strength = reader.ReadInt32(), //125
|
Strength = reader.ReadInt32(), //125
|
||||||
Dexterity = reader.ReadInt32(), //129
|
Dexterity = reader.ReadInt32(), //129
|
||||||
Intelligence = reader.ReadInt32(), //133
|
Intelligence = reader.ReadInt32(), //133
|
||||||
|
@ -19,10 +16,8 @@ public static class ItemReaderExtensions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ElementalStats ReadElementalStats(this BinaryReader reader)
|
public static ElementalStats ReadElementalStats(this BinaryReader reader) {
|
||||||
{
|
return new ElementalStats {
|
||||||
return new ElementalStats
|
|
||||||
{
|
|
||||||
MinimumFireDamage = reader.ReadInt32(), //149
|
MinimumFireDamage = reader.ReadInt32(), //149
|
||||||
MinimumWaterDamage = reader.ReadInt32(), //153
|
MinimumWaterDamage = reader.ReadInt32(), //153
|
||||||
MinimumDarkDamage = reader.ReadInt32(), //157
|
MinimumDarkDamage = reader.ReadInt32(), //157
|
||||||
|
@ -42,52 +37,44 @@ public static class ItemReaderExtensions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ContainedItem[] ReadContainedItems(this BinaryReader reader)
|
public static ContainedItem[] ReadContainedItems(this BinaryReader reader) {
|
||||||
{
|
|
||||||
var list = new ContainedItem[5];
|
var list = new ContainedItem[5];
|
||||||
//893
|
//893
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++) {
|
||||||
{
|
|
||||||
list[i].ID = reader.ReadInt16();
|
list[i].ID = reader.ReadInt16();
|
||||||
}
|
}
|
||||||
|
|
||||||
//903
|
//903
|
||||||
for (var i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++) {
|
||||||
{
|
|
||||||
list[i].ObtainChance = reader.ReadSingle();
|
list[i].ObtainChance = reader.ReadSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CraftMaterial[] ReadCraftMaterial(this BinaryReader reader)
|
public static CraftMaterial[] ReadCraftMaterial(this BinaryReader reader) {
|
||||||
{
|
|
||||||
var mats = new CraftMaterial[4];
|
var mats = new CraftMaterial[4];
|
||||||
//329
|
//329
|
||||||
for (var i = 0; i < 4; ++i)
|
for (var i = 0; i < 4; ++i) {
|
||||||
{
|
|
||||||
mats[i].ID = reader.ReadUInt32();
|
mats[i].ID = reader.ReadUInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
//345
|
//345
|
||||||
for (var i = 0; i < 4; ++i)
|
for (var i = 0; i < 4; ++i) {
|
||||||
{
|
|
||||||
mats[i].ID = reader.ReadUInt32();
|
mats[i].ID = reader.ReadUInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
return mats;
|
return mats;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemOptions ReadItemOptions(this BinaryReader reader)
|
public static ItemOptions ReadItemOptions(this BinaryReader reader) {
|
||||||
{
|
|
||||||
var options = new ItemOptions();
|
var options = new ItemOptions();
|
||||||
|
|
||||||
options.OptionAvailable = reader.ReadInt32() == 1; //819
|
options.OptionAvailable = reader.ReadInt32() == 1; //819
|
||||||
|
|
||||||
var optionIDs = new List<uint>(4);
|
var optionIDs = new List<uint>(4);
|
||||||
//823
|
//823
|
||||||
for (var i = 0; i < 3; i++)
|
for (var i = 0; i < 3; i++) {
|
||||||
{
|
|
||||||
optionIDs.Add(reader.ReadUInt32());
|
optionIDs.Add(reader.ReadUInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
|
|
||||||
namespace Wonderking.Packets;
|
|
||||||
|
|
||||||
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
|
||||||
public interface IPacket
|
|
||||||
{
|
|
||||||
public void Deserialize(byte[] data);
|
|
||||||
public byte[] Serialize();
|
|
||||||
}
|
|
|
@ -1,21 +1,16 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Incoming;
|
namespace Wonderking.Packets.Incoming;
|
||||||
|
|
||||||
[PacketId(OperationCode.ChannelSelection)]
|
[WonderkingPacketId(OperationCode.ChannelSelection)]
|
||||||
public class ChannelSelectionPacket : IPacket
|
public class ChannelSelectionPacket : IIncomingPacket {
|
||||||
{
|
|
||||||
public required ushort ServerId { get; set; }
|
public required ushort ServerId { get; set; }
|
||||||
public required ushort ChannelId { get; set; }
|
public required ushort ChannelId { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public void Deserialize(byte[] data) {
|
||||||
{
|
|
||||||
ServerId = BitConverter.ToUInt16(data, 0);
|
ServerId = BitConverter.ToUInt16(data, 0);
|
||||||
ChannelId = BitConverter.ToUInt16(data, 2);
|
ChannelId = BitConverter.ToUInt16(data, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Game.Data.Character;
|
using Wonderking.Game.Data.Character;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Incoming;
|
namespace Wonderking.Packets.Incoming;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterCreation)]
|
[WonderkingPacketId(OperationCode.CharacterCreation)]
|
||||||
public class CharacterCreationPacket : IPacket
|
public class CharacterCreationPacket : IIncomingPacket {
|
||||||
{
|
|
||||||
public required byte Slot { get; set; }
|
public required byte Slot { get; set; }
|
||||||
public required byte Unknown { get; set; }
|
public required byte Unknown { get; set; }
|
||||||
public required ushort Id { get; set; }
|
public required ushort Id { get; set; }
|
||||||
|
@ -20,8 +20,7 @@ public class CharacterCreationPacket : IPacket
|
||||||
public required byte Shirt { get; set; }
|
public required byte Shirt { get; set; }
|
||||||
public required byte Pants { get; set; }
|
public required byte Pants { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public void Deserialize(byte[] data) {
|
||||||
{
|
|
||||||
Slot = data[0];
|
Slot = data[0];
|
||||||
Unknown = data[1];
|
Unknown = data[1];
|
||||||
Id = BitConverter.ToUInt16(data, 2);
|
Id = BitConverter.ToUInt16(data, 2);
|
||||||
|
@ -33,9 +32,4 @@ public class CharacterCreationPacket : IPacket
|
||||||
Shirt = data[28];
|
Shirt = data[28];
|
||||||
Pants = data[29];
|
Pants = data[29];
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Incoming;
|
namespace Wonderking.Packets.Incoming;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterDeletion)]
|
[WonderkingPacketId(OperationCode.CharacterDeletion)]
|
||||||
public class CharacterDeletePacket : IPacket
|
public class CharacterDeletePacket : IIncomingPacket {
|
||||||
{
|
public required byte Slot { get; set; }
|
||||||
public byte Slot { get; set; }
|
public required string Name { get; set; }
|
||||||
public string Name { get; set; }
|
public required uint Unknown { get; set; }
|
||||||
public uint Unknown { get; set; }
|
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public void Deserialize(byte[] data) {
|
||||||
{
|
|
||||||
Span<byte> span = data;
|
Span<byte> span = data;
|
||||||
Slot = span[0];
|
Slot = span[0];
|
||||||
Name = Encoding.ASCII.GetString(span.Slice(1, 20)).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
Name = Encoding.ASCII.GetString(span.Slice(1, 20)).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||||
Unknown = BitConverter.ToUInt32(span.Slice(21, 4));
|
Unknown = BitConverter.ToUInt32(span.Slice(21, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Incoming;
|
namespace Wonderking.Packets.Incoming;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterNameCheck)]
|
[WonderkingPacketId(OperationCode.CharacterNameCheck)]
|
||||||
public class CharacterNameCheckPacket : IPacket
|
public class CharacterNameCheckPacket : IIncomingPacket {
|
||||||
{
|
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public void Deserialize(byte[] data) {
|
||||||
{
|
|
||||||
Name = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
Name = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,19 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Incoming;
|
namespace Wonderking.Packets.Incoming;
|
||||||
|
|
||||||
[PacketId(OperationCode.LoginInfo)]
|
[WonderkingPacketId(OperationCode.LoginInfo)]
|
||||||
public class LoginInfoPacket : IPacket
|
public class LoginInfoPacket : IIncomingPacket {
|
||||||
{
|
|
||||||
public required string Username { get; set; }
|
public required string Username { get; set; }
|
||||||
|
|
||||||
public required string Password { get; set; }
|
public required string Password { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public void Deserialize(byte[] data) {
|
||||||
{
|
|
||||||
Username = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
Username = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||||
// Remove unnecessary Symbols
|
// Remove unnecessary Symbols
|
||||||
Password = Encoding.ASCII.GetString(data, 20, 31).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
Password = Encoding.ASCII.GetString(data, 20, 31).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> dataSpan = stackalloc byte[20 + 31];
|
|
||||||
var usernameBytes = Encoding.ASCII.GetBytes(Username);
|
|
||||||
var passwordBytes = Encoding.ASCII.GetBytes(Password);
|
|
||||||
for (var i = 0; i < 20 || i < Username.Length; i++)
|
|
||||||
{
|
|
||||||
dataSpan[i] = usernameBytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < 31 || i < Password.Length; i++)
|
|
||||||
{
|
|
||||||
dataSpan[20 + i] = passwordBytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataSpan.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Wonderking.Packets;
|
namespace Wonderking.Packets;
|
||||||
|
|
||||||
public enum OperationCode : ushort
|
public enum OperationCode : ushort {
|
||||||
{
|
|
||||||
LoginInfo = 11,
|
LoginInfo = 11,
|
||||||
LoginResponse = 12,
|
LoginResponse = 12,
|
||||||
ChannelSelection = 13,
|
ChannelSelection = 13,
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Outgoing.Data;
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.ChannelSelectionResponse)]
|
[WonderkingPacketId(OperationCode.ChannelSelectionResponse)]
|
||||||
public class ChannelSelectionResponsePacket : IPacket
|
public class ChannelSelectionResponsePacket : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required byte ChannelIsFullFlag { get; set; }
|
public required byte ChannelIsFullFlag { get; set; }
|
||||||
public required string Endpoint { get; set; }
|
public required string Endpoint { get; set; }
|
||||||
public required ushort Port { get; set; }
|
public required ushort Port { get; set; }
|
||||||
public required CharacterData[] Characters { get; set; }
|
public required CharacterData[] Characters { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> data = stackalloc byte[1 + 16 + 2 + 1 + 132 * Characters.Length];
|
Span<byte> data = stackalloc byte[1 + 16 + 2 + 1 + 132 * Characters.Length];
|
||||||
data.Clear();
|
data.Clear();
|
||||||
data[0] = ChannelIsFullFlag;
|
data[0] = ChannelIsFullFlag;
|
||||||
|
@ -29,8 +23,7 @@ public class ChannelSelectionResponsePacket : IPacket
|
||||||
data[19] = (byte)Characters.Length;
|
data[19] = (byte)Characters.Length;
|
||||||
|
|
||||||
// Character Data
|
// Character Data
|
||||||
for (var i = 0; i < Characters.Length; i++)
|
for (var i = 0; i < Characters.Length; i++) {
|
||||||
{
|
|
||||||
var offset = 20 + i * 132;
|
var offset = 20 + i * 132;
|
||||||
var character = Characters[i];
|
var character = Characters[i];
|
||||||
// Character Data
|
// Character Data
|
||||||
|
@ -58,8 +51,7 @@ public class ChannelSelectionResponsePacket : IPacket
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 44, 4), character.Health);
|
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 44, 4), character.Health);
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 48, 4), character.Mana);
|
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 48, 4), character.Mana);
|
||||||
|
|
||||||
for (var j = 0; j < 20; j++)
|
for (var j = 0; j < 20; j++) {
|
||||||
{
|
|
||||||
// Equipped Items
|
// Equipped Items
|
||||||
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(offset + 52 + j * 2, 2),
|
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(offset + 52 + j * 2, 2),
|
||||||
character.EquippedItems.Length > j ? character.EquippedItems[j] : (ushort)0);
|
character.EquippedItems.Length > j ? character.EquippedItems[j] : (ushort)0);
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Outgoing.Data;
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterCreationResponse)]
|
[WonderkingPacketId(OperationCode.CharacterCreationResponse)]
|
||||||
public class CharacterCreationResponsePacket : IPacket
|
public class CharacterCreationResponsePacket : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required CharacterData Character { get; set; }
|
public required CharacterData Character { get; set; }
|
||||||
public required int Slot { get; set; }
|
public required int Slot { get; set; }
|
||||||
public required bool isDuplicate { get; set; }
|
public required bool isDuplicate { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> data = stackalloc byte[1 + 132];
|
Span<byte> data = stackalloc byte[1 + 132];
|
||||||
data[0] = isDuplicate ? (byte)1 : (byte)0;
|
data[0] = isDuplicate ? (byte)1 : (byte)0;
|
||||||
|
|
||||||
|
@ -48,8 +42,7 @@ public class CharacterCreationResponsePacket : IPacket
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(45, 4), Character.Health);
|
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(45, 4), Character.Health);
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(49, 4), Character.Mana);
|
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(49, 4), Character.Mana);
|
||||||
|
|
||||||
for (var i = 0; i < 20; i++)
|
for (var i = 0; i < 20; i++) {
|
||||||
{
|
|
||||||
// Equipped Items
|
// Equipped Items
|
||||||
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(53 + i * 2, 2),
|
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(53 + i * 2, 2),
|
||||||
Character.EquippedItems.Length > i ? Character.EquippedItems[i] : (ushort)0);
|
Character.EquippedItems.Length > i ? Character.EquippedItems[i] : (ushort)0);
|
||||||
|
|
|
@ -1,21 +1,14 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using NotSupportedException = System.NotSupportedException;
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterDeletionResponse)]
|
[WonderkingPacketId(OperationCode.CharacterDeletionResponse)]
|
||||||
public class CharacterDeleteResponsePacket : IPacket
|
public class CharacterDeleteResponsePacket : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required byte HasToBeZero { get; set; }
|
public required byte HasToBeZero { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> data = stackalloc byte[1];
|
Span<byte> data = stackalloc byte[1];
|
||||||
data[0] = HasToBeZero;
|
data[0] = HasToBeZero;
|
||||||
return data.ToArray();
|
return data.ToArray();
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterNameCheckResponse)]
|
[WonderkingPacketId(OperationCode.CharacterNameCheckResponse)]
|
||||||
public class CharacterNameCheckPacketResponse : IPacket
|
public class CharacterNameCheckPacketResponse : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required bool IsTaken { get; set; }
|
public required bool IsTaken { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> data = stackalloc byte[1];
|
Span<byte> data = stackalloc byte[1];
|
||||||
data[0] = IsTaken ? (byte)1 : (byte)0;
|
data[0] = IsTaken ? (byte)1 : (byte)0;
|
||||||
return data.ToArray();
|
return data.ToArray();
|
||||||
|
|
|
@ -1,26 +1,19 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.CharacterSelectionSetGuildName)]
|
[WonderkingPacketId(OperationCode.CharacterSelectionSetGuildName)]
|
||||||
public class CharacterSelectionSetGuildNamePacket : IPacket
|
public class CharacterSelectionSetGuildNamePacket : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required string[] GuildNames { get; set; }
|
public required string[] GuildNames { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
Span<byte> data = stackalloc byte[1 + (1 + 16 + 1) * GuildNames.Length];
|
Span<byte> data = stackalloc byte[1 + (1 + 16 + 1) * GuildNames.Length];
|
||||||
data.Clear();
|
data.Clear();
|
||||||
data[0] = (byte)GuildNames.Length;
|
data[0] = (byte)GuildNames.Length;
|
||||||
for (var i = 0; i < GuildNames.Length; i++)
|
for (var i = 0; i < GuildNames.Length; i++) {
|
||||||
{
|
|
||||||
data[1 + i * (1 + 16 + 1)] = (byte)i;
|
data[1 + i * (1 + 16 + 1)] = (byte)i;
|
||||||
Encoding.ASCII.GetBytes(GuildNames[i], data.Slice(2 + i * (1 + 16 + 1), 16));
|
Encoding.ASCII.GetBytes(GuildNames[i], data.Slice(2 + i * (1 + 16 + 1), 16));
|
||||||
// Null terminator
|
// Null terminator
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
@ -8,8 +8,7 @@ namespace Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
[Owned]
|
[Owned]
|
||||||
public class BaseStats
|
public class BaseStats {
|
||||||
{
|
|
||||||
[JsonPropertyName("strength")] public required short Strength { get; set; }
|
[JsonPropertyName("strength")] public required short Strength { get; set; }
|
||||||
[JsonPropertyName("dexterity")] public required short Dexterity { get; set; }
|
[JsonPropertyName("dexterity")] public required short Dexterity { get; set; }
|
||||||
[JsonPropertyName("intelligence")] public required short Intelligence { get; set; }
|
[JsonPropertyName("intelligence")] public required short Intelligence { get; set; }
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using Wonderking.Game.Data.Character;
|
using Wonderking.Game.Data.Character;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing.Data;
|
namespace Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
public struct CharacterData
|
public struct CharacterData {
|
||||||
{
|
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public required JobData Job { get; set; }
|
public required JobData Job { get; set; }
|
||||||
public required Gender Gender { get; set; }
|
public required Gender Gender { get; set; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -7,8 +7,7 @@ namespace Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
[Owned]
|
[Owned]
|
||||||
public class JobData
|
public class JobData {
|
||||||
{
|
|
||||||
public required byte FirstJob { get; set; }
|
public required byte FirstJob { get; set; }
|
||||||
public required byte SecondJob { get; set; }
|
public required byte SecondJob { get; set; }
|
||||||
public required byte ThirdJob { get; set; }
|
public required byte ThirdJob { get; set; }
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing.Data;
|
namespace Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
public enum LoginResponseReason : byte
|
public enum LoginResponseReason : byte {
|
||||||
{
|
|
||||||
Ok,
|
Ok,
|
||||||
AccountDoesNotExit,
|
AccountDoesNotExit,
|
||||||
WrongPassword,
|
WrongPassword,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing.Data;
|
namespace Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Auto)]
|
[StructLayout(LayoutKind.Auto)]
|
||||||
public struct ServerChannelData
|
public struct ServerChannelData {
|
||||||
{
|
|
||||||
public ushort ServerId { get; set; }
|
public ushort ServerId { get; set; }
|
||||||
public ushort ChannelId { get; set; }
|
public ushort ChannelId { get; set; }
|
||||||
public byte LoadPercentage { get; set; }
|
public byte LoadPercentage { get; set; }
|
||||||
|
|
|
@ -1,36 +1,20 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
using Wonderking.Packets.Outgoing.Data;
|
using Wonderking.Packets.Outgoing.Data;
|
||||||
|
|
||||||
namespace Wonderking.Packets.Outgoing;
|
namespace Wonderking.Packets.Outgoing;
|
||||||
|
|
||||||
[PacketId(OperationCode.LoginResponse)]
|
[WonderkingPacketId(OperationCode.LoginResponse)]
|
||||||
public class LoginResponsePacket : IPacket
|
public class LoginResponsePacket : IOutgoingPacket {
|
||||||
{
|
|
||||||
public required LoginResponseReason ResponseReason { get; set; }
|
public required LoginResponseReason ResponseReason { get; set; }
|
||||||
public required byte UnknownFlag { get; set; } = 1;
|
public required byte UnknownFlag { get; set; } = 1;
|
||||||
public required bool IsGameMaster { get; set; }
|
public required bool IsGameMaster { get; set; }
|
||||||
|
|
||||||
public required ServerChannelData[] ChannelData { get; set; }
|
public required ServerChannelData[] ChannelData { get; set; }
|
||||||
|
|
||||||
public void Deserialize(byte[] data)
|
public byte[] Serialize() {
|
||||||
{
|
|
||||||
ResponseReason = (LoginResponseReason)data[0];
|
|
||||||
UnknownFlag = data[1];
|
|
||||||
IsGameMaster = BitConverter.ToBoolean(data, 2);
|
|
||||||
var channelAmount = BitConverter.ToUInt16(data, 3);
|
|
||||||
const int sizeOfServerChannelData = 5;
|
|
||||||
ChannelData = Enumerable.Repeat(0, channelAmount).Select(i => new ServerChannelData
|
|
||||||
{
|
|
||||||
ServerId = BitConverter.ToUInt16(data, 5 + 0 + i * sizeOfServerChannelData),
|
|
||||||
ChannelId = BitConverter.ToUInt16(data, 5 + 2 + i * sizeOfServerChannelData),
|
|
||||||
LoadPercentage = data[5 + 4 + i * sizeOfServerChannelData]
|
|
||||||
}).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize()
|
|
||||||
{
|
|
||||||
const int sizeOfServerChannelData = 5;
|
const int sizeOfServerChannelData = 5;
|
||||||
Span<byte> dataSpan = stackalloc byte[5 + ChannelData.Length * sizeOfServerChannelData];
|
Span<byte> dataSpan = stackalloc byte[5 + ChannelData.Length * sizeOfServerChannelData];
|
||||||
dataSpan.Clear();
|
dataSpan.Clear();
|
||||||
|
@ -39,8 +23,7 @@ public class LoginResponsePacket : IPacket
|
||||||
dataSpan[2] = BitConverter.GetBytes(IsGameMaster)[0];
|
dataSpan[2] = BitConverter.GetBytes(IsGameMaster)[0];
|
||||||
BinaryPrimitives.WriteUInt16LittleEndian(dataSpan.Slice(3, 2), (ushort)ChannelData.Length);
|
BinaryPrimitives.WriteUInt16LittleEndian(dataSpan.Slice(3, 2), (ushort)ChannelData.Length);
|
||||||
|
|
||||||
for (var i = 0; i < ChannelData.Length; i++)
|
for (var i = 0; i < ChannelData.Length; i++) {
|
||||||
{
|
|
||||||
var bytesOfServerId = BitConverter.GetBytes(ChannelData[i].ServerId);
|
var bytesOfServerId = BitConverter.GetBytes(ChannelData[i].ServerId);
|
||||||
var bytesOfChannelId = BitConverter.GetBytes(ChannelData[i].ChannelId);
|
var bytesOfChannelId = BitConverter.GetBytes(ChannelData[i].ChannelId);
|
||||||
dataSpan[5 + 0 + i * sizeOfServerChannelData] = bytesOfServerId[0];
|
dataSpan[5 + 0 + i * sizeOfServerChannelData] = bytesOfServerId[0];
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.
|
|
||||||
|
|
||||||
namespace Wonderking.Packets;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
|
||||||
public class PacketIdAttribute : Attribute
|
|
||||||
{
|
|
||||||
public PacketIdAttribute(OperationCode code)
|
|
||||||
{
|
|
||||||
Code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OperationCode Code { get; }
|
|
||||||
}
|
|
11
Wonderking/Packets/WonderkingPacketIdAttribute.cs
Normal file
11
Wonderking/Packets/WonderkingPacketIdAttribute.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using RaiNote.PacketMediator;
|
||||||
|
|
||||||
|
namespace Wonderking.Packets;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||||
|
public class WonderkingPacketIdAttribute : PacketIdAttribute<OperationCode> {
|
||||||
|
public WonderkingPacketIdAttribute(OperationCode code) : base(code) {
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue