Commit b3a41aed authored by nanahira's avatar nanahira

Merge branch 'server-develop' into server

parents 55f4fe4a 5178a0a6
...@@ -6,6 +6,7 @@ source .ci/asset-branch ...@@ -6,6 +6,7 @@ source .ci/asset-branch
apt update && apt -y install wget git libarchive-tools sqlite3 apt update && apt -y install wget git libarchive-tools sqlite3
git clone --depth=1 -b "$ASSET_BRANCH_NAME" https://code.moenext.com/mycard/ygopro-database git clone --depth=1 -b "$ASSET_BRANCH_NAME" https://code.moenext.com/mycard/ygopro-database
cp -rf ./ygopro-database/locales/$TARGET_LOCALE/strings.conf . cp -rf ./ygopro-database/locales/$TARGET_LOCALE/strings.conf .
cp -rf ./ygopro-database/locales/$TARGET_LOCALE/servers.conf .
rm -f cards.cdb rm -f cards.cdb
sqlite3 ./ygopro-database/locales/$TARGET_LOCALE/cards.cdb .dump | sqlite3 cards.cdb sqlite3 ./ygopro-database/locales/$TARGET_LOCALE/cards.cdb .dump | sqlite3 cards.cdb
# ygopro-images # ygopro-images
......
#!/bin/sh
set -x
set -o errexit
if [ -n "$NO_AUDIO" ]; then
echo "Skipping opus build because NO_AUDIO is set"
exit 0
fi
cd miniaudio
external_built_dir="$PWD/external-built"
is_macos=false
if [ "$(uname)" = "Darwin" ]; then
is_macos=true
fi
maybe_patch_configure() {
if $is_macos; then
sed -i.bak 's/-force_cpusubtype_ALL//g' configure*
fi
}
build_single_thing() {
lib_name="$1"
cd "external/$lib_name"
shift
maybe_patch_configure
PKG_CONFIG_PATH="$external_built_dir/lib/pkgconfig" CFLAGS="$OPUS_FLAGS" CXXFLAGS="$OPUS_FLAGS" ./configure --prefix="$external_built_dir" --enable-static=yes --enable-shared=no "$@"
make -j$(nproc)
make install
cd ../..
}
build_single_thing ogg
build_single_thing opus
build_single_thing opusfile --disable-examples --disable-http
build_single_thing vorbis --with-ogg="$external_built_dir"
cd ..
#!/bin/bash
libs_to_configure=(
"ogg"
# "opus"
)
cd miniaudio/external
for lib in "${libs_to_configure[@]}"; do
cd $lib
./configure
cd ..
done
#!/bin/sh
set -x
set -o errexit
cd event
./configure --disable-openssl --enable-static=yes --enable-shared=no
sed -f make-event-config.sed < config.h > ./include/event2/event-config.h
cd ..
...@@ -4,30 +4,19 @@ set -o errexit ...@@ -4,30 +4,19 @@ set -o errexit
TARGET_PLATFORM=$(arch) TARGET_PLATFORM=$(arch)
TARGET_YGOPRO_BINARY_PATH=./ygopro-platforms/ygopro-platform-$TARGET_PLATFORM TARGET_YGOPRO_BINARY_PATH=./ygopro-platforms/ygopro-platform-$TARGET_PLATFORM
export EVENT_INCLUDE_DIR=$PWD/libevent-stable/include
export EVENT_LIB_DIR=$PWD/libevent-stable/lib ./.ci/configure-audio.sh
export OPUS_INCLUDE_DIR=$PWD/miniaudio/external-built/include/opus
export OPUS_LIB_DIR=$PWD/miniaudio/external-built/lib rm -rf sqlite3/VERSION sqlite3/version
export OPUSFILE_INCLUDE_DIR=$PWD/miniaudio/external-built/include/opus
export OPUSFILE_LIB_DIR=$PWD/miniaudio/external-built/lib ./premake5 gmake --cc=clang
export VORBIS_INCLUDE_DIR=$PWD/miniaudio/external-built/include
export VORBIS_LIB_DIR=$PWD/miniaudio/external-built/lib
export OGG_INCLUDE_DIR=$PWD/miniaudio/external-built/include
export OGG_LIB_DIR=$PWD/miniaudio/external-built/lib
export ACLOCAL=aclocal
export AUTOMAKE=automake
./.ci/libevent-prebuild.sh
./.ci/build-opus.sh
./premake5 gmake --cc=clang --build-freetype --build-sqlite
cd build cd build
make config=release -j$(sysctl -n hw.ncpu) make config=release -j$(sysctl -n hw.ncpu)
cd .. cd ..
mkdir ygopro-platforms mkdir ygopro-platforms
mv bin/release/YGOPro.app $TARGET_YGOPRO_BINARY_PATH mv bin/release/YGOPro $TARGET_YGOPRO_BINARY_PATH
#if [[ $TARGET_PLATFORM == "x86" ]]; then #if [[ $TARGET_PLATFORM == "x86" ]]; then
# install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/../Frameworks/libirrklang.dylib $TARGET_YGOPRO_BINARY_PATH # install_name_tool -change /usr/local/lib/libirrklang.dylib @executable_path/../Frameworks/libirrklang.dylib $TARGET_YGOPRO_BINARY_PATH
......
#!/bin/sh
set -x
set -o errexit
# PROCESSOR_COUNT=4
if [ -d "libevent-stable" ]; then
rm -rf libevent-stable
fi
if [ ! -d "libevent-2.0.22-stable" ]; then
wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/libevent-2.0.22-stable.tar.gz | tar zfx -
fi
install_path="$PWD/libevent-stable"
cd libevent-2.0.22-stable
./configure "--prefix=$install_path" --disable-openssl --enable-static=yes --enable-shared=no "$@"
make -j$(nproc)
make install
cd ..
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro cards.cdb locales fonts sound textures strings.conf system.conf pack) ARCHIVE_FILES=(ygopro cards.cdb locales fonts sound textures strings.conf system.conf servers.conf pack)
if [[ -z "$TARGET_PLATFORM" ]]; then if [[ -z "$TARGET_PLATFORM" ]]; then
TARGET_PLATFORM=linux TARGET_PLATFORM=linux
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay windbot bot bot.conf locales fonts pack) ARCHIVE_FILES=(ygopro LICENSE README.md lflist.conf strings.conf system.conf servers.conf cards.cdb script textures deck single pics replay windbot bot bot.conf locales fonts pack)
# TARGET_LOCALE # TARGET_LOCALE
# ARCHIVE_SUFFIX # ARCHIVE_SUFFIX
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro.app cards.cdb locales fonts sound textures strings.conf system.conf pack) ARCHIVE_FILES=(ygopro.app cards.cdb locales fonts sound textures strings.conf system.conf servers.conf pack)
if [[ -z "$TARGET_PLATFORM" ]]; then if [[ -z "$TARGET_PLATFORM" ]]; then
TARGET_PLATFORM=darwin TARGET_PLATFORM=darwin
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro.app LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound windbot bot bot.conf locales fonts pack) ARCHIVE_FILES=(ygopro.app LICENSE README.md lflist.conf strings.conf system.conf servers.conf cards.cdb script textures deck single pics replay sound windbot bot bot.conf locales fonts pack)
# TARGET_LOCALE # TARGET_LOCALE
# ARCHIVE_SUFFIX # ARCHIVE_SUFFIX
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack) ARCHIVE_FILES=(ygopro.exe vcomp140.dll LICENSE README.md lflist.conf strings.conf system.conf servers.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack)
if [[ "$TARGET_LOCALE" == "zh-CN" ]]; then if [[ "$TARGET_LOCALE" == "zh-CN" ]]; then
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro) ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro.exe cards.cdb locales fonts sound textures strings.conf system.conf skin pack) ARCHIVE_FILES=(ygopro.exe vcomp140.dll cards.cdb locales fonts sound textures strings.conf system.conf servers.conf skin pack)
if [[ -z "$TARGET_PLATFORM" ]]; then if [[ -z "$TARGET_PLATFORM" ]]; then
TARGET_PLATFORM=win32 TARGET_PLATFORM=win32
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
set -x set -x
set -o errexit set -o errexit
ARCHIVE_FILES=(ygopro.exe LICENSE README.md lflist.conf strings.conf system.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack) ARCHIVE_FILES=(ygopro.exe vcomp140.dll LICENSE README.md lflist.conf strings.conf system.conf servers.conf cards.cdb script textures deck single pics replay sound bot.conf Bot.exe WindBot locales fonts skin pack)
if [[ "$TARGET_LOCALE" == "zh-CN" && "$ARCHIVE_SUFFIX" != "zst" ]]; then if [[ "$TARGET_LOCALE" == "zh-CN" && "$ARCHIVE_SUFFIX" != "zst" ]]; then
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro) ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
#!/bin/bash #!/bin/bash
set -x set -x
set -o errexit set -o errexit
source .ci/asset-branch
IRRLICHT_REPO_URL="https://code.moenext.com/mycard/irrlicht-new.git" source .ci/prepare-repo
IRRLICHT_BRANCH_NAME="$ASSET_BRANCH_NAME" prepare_repo "https://code.moenext.com/mycard/irrlicht-new.git" "irrlicht"
if [ ! -d "irrlicht" ]; then
git clone --depth=1 --branch "$IRRLICHT_BRANCH_NAME" "$IRRLICHT_REPO_URL" irrlicht
else
cd irrlicht
git fetch origin "$IRRLICHT_BRANCH_NAME"
git checkout "$IRRLICHT_BRANCH_NAME"
git reset --hard origin/"$IRRLICHT_BRANCH_NAME"
cd ..
fi
#!/bin/sh #!/bin/bash
set -x set -x
set -o errexit set -o errexit
if [ ! -d "miniaudio" ]; then source .ci/prepare-repo
git clone --depth=1 --branch 0.11.22 https://github.com/mackron/miniaudio prepare_repo "https://code.moenext.com/mycard/miniaudio.git" "miniaudio"
fi
cp -rf miniaudio/extras/miniaudio_split/miniaudio.* miniaudio/ cp -rf miniaudio/extras/miniaudio_split/miniaudio.* miniaudio/
...@@ -20,7 +19,7 @@ install_external() { ...@@ -20,7 +19,7 @@ install_external() {
fi fi
} }
install_external "ogg" "https://github.com/xiph/ogg/releases/download/v1.3.5/libogg-1.3.5.tar.gz" install_external "ogg" "https://mat-cacher.moenext.com/https://github.com/xiph/ogg/releases/download/v1.3.5/libogg-1.3.5.tar.gz"
install_external "opus" "https://github.com/xiph/opus/releases/download/v1.5.2/opus-1.5.2.tar.gz" install_external "opus" "https://mat-cacher.moenext.com/https://github.com/xiph/opus/releases/download/v1.5.2/opus-1.5.2.tar.gz"
install_external "opusfile" "https://github.com/xiph/opusfile/releases/download/v0.12/opusfile-0.12.tar.gz" install_external "opusfile" "https://mat-cacher.moenext.com/https://github.com/xiph/opusfile/releases/download/v0.12/opusfile-0.12.tar.gz"
install_external "vorbis" "https://github.com/xiph/vorbis/releases/download/v1.3.7/libvorbis-1.3.7.tar.gz" install_external "vorbis" "https://mat-cacher.moenext.com/https://github.com/xiph/vorbis/releases/download/v1.3.7/libvorbis-1.3.7.tar.gz"
source .ci/asset-branch
BRANCH_NAME="$ASSET_BRANCH_NAME"
prepare_repo() {
REPO_URL="$1"
TARGET_DIR_NAME="$2"
if [ ! -d "$TARGET_DIR_NAME" ]; then
echo "Cloning repository $REPO_URL branch $BRANCH_NAME into $TARGET_DIR_NAME"
git clone --depth=1 --branch "$BRANCH_NAME" "$REPO_URL" "$TARGET_DIR_NAME"
else
echo "Repository $REPO_URL already exists in $TARGET_DIR_NAME, updating to $BRANCH_NAME..."
cd "$TARGET_DIR_NAME"
git remote set-url origin "$REPO_URL"
git fetch origin "$BRANCH_NAME"
git checkout "$BRANCH_NAME"
git reset --hard origin/"$BRANCH_NAME"
cd ..
fi
}
This diff is collapsed.
name: Automated Test Build (Server Mode)
on:
push:
branches: [ "server" ]
pull_request:
branches: [ "server" ]
jobs:
build-windows:
strategy:
fail-fast: false
matrix:
name:
- windows
- windows-x64
- windows-ygopro2-ai-server
# - windows-2025
include:
- name: windows
os: windows-2022
vs: vs2022
- name: windows-x64
os: windows-2022
vs: vs2022
x64: true
# - name: windows-2025
# os: windows-2025
# vs: vs2025 # to be enabled after the release of Visual Studio 2025
- name: windows-ygopro2-ai-server
os: windows-2022
vs: vs2022
x64: true
ygopro2: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository with submodules
uses: actions/checkout@v4
with:
fetch-depth: 1
submodules: true
- name: Update submodules
run: |
cd ocgcore
git checkout master
git pull origin master
cd ..
# cd script
# git checkout master
# git pull origin master
# cd ..
- name: Download premake
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta6/premake-5.0.0-beta6-windows.zip
filename: premake5.zip
- name: Extract premake
run: |
7z x ${{ steps.premake.outputs.filepath }}
- name: Download libevent
id: libevent
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/libevent/libevent/releases/download/release-2.0.22-stable/libevent-2.0.22-stable.tar.gz
filename: libevent.tar.gz
- name: Extract libevent
run: |
tar xf ${{ steps.libevent.outputs.filepath }}
move libevent-2.0.22-stable event
- name: Download lua
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
- name: Extract lua
run: |
tar xf ${{ steps.lua.outputs.filepath }}
move lua-5.4.7 lua
- name: Download sqlite
id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
- name: Extract sqlite
run: |
7z x ${{ steps.sqlite.outputs.filepath }}
move sqlite-amalgamation-3490100 sqlite3
- name: Download irrlicht
if: matrix.ygopro2 == true
run: |
git clone --depth=1 https://github.com/mercury233/irrlicht
- name: Copy premake files
run: |
xcopy /E premake\* .
xcopy /E resource\* .
- name: Use premake to generate Visual Studio solution
run: |
.\premake5.exe ${{ matrix.vs }} ${{ matrix.ygopro2 && '--server-pro2-support' || '' }}
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Build solution
run: |
MSBuild.exe build\YGOPro.sln /m /p:Configuration=Release /p:Platform=${{ matrix.x64 && 'x64' || 'Win32' }}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: YGOPro-Server-${{ matrix.name }}
path: |
bin/release/x86/ygopro.exe
bin/release/x64/ygopro.exe
bin/release/x64/AI.Server.exe
build-linux:
strategy:
fail-fast: false
matrix:
name:
- ubuntu-22
- ubuntu-24
- ubuntu-static-link
- ubuntu-zip-support
include:
- name: ubuntu-22
os: ubuntu-22.04
premake-version: 5.0.0-beta4
- name: ubuntu-24
os: ubuntu-24.04
premake-version: 5.0.0-beta6
- name: ubuntu-static-link
os: ubuntu-22.04
premake-version: 5.0.0-beta4
static-link: true
- name: ubuntu-zip-support
os: ubuntu-22.04
premake-version: 5.0.0-beta4
zip-support: true
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository with submodules
uses: actions/checkout@v4
with:
fetch-depth: 1
submodules: true
- name: Update submodules
run: |
cd ocgcore
git checkout master
git pull origin master
cd ..
# cd script
# git checkout master
# git pull origin master
# cd ..
- name: Install dependencies
if: matrix.static-link != true
run: |
sudo apt-get update
sudo apt-get install -y libevent-dev libsqlite3-dev
- name: Download premake
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v${{ matrix.premake-version }}/premake-${{ matrix.premake-version }}-linux.tar.gz
filename: premake5.tar.gz
- name: Extract premake
run: |
tar xf ${{ steps.premake.outputs.filepath }}
chmod +x ./premake5
- name: Download libevent
if: matrix.static-link == true
id: libevent
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
filename: libevent.tar.gz
- name: Extract libevent
if: matrix.static-link == true
run: |
tar xf ${{ steps.libevent.outputs.filepath }}
mv libevent-2.1.12-stable event
- name: Configure libevent
if: matrix.static-link == true
run: |
cd event
./configure --disable-openssl --enable-static=yes --enable-shared=no
sed -f make-event-config.sed < config.h > ./include/event2/event-config.h
cd ..
- name: Download lua
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
- name: Extract lua
run: |
tar xf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.7 lua
- name: Download sqlite
if: matrix.static-link == true
id: sqlite
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip
- name: Extract sqlite
if: matrix.static-link == true
run: |
7z x ${{ steps.sqlite.outputs.filepath }}
mv sqlite-amalgamation-3490100 sqlite3
- name: Download irrlicht
if: matrix.zip-support == true
run: |
git clone --depth=1 https://github.com/mercury233/irrlicht
- name: Copy premake files
run: |
cp -r premake/* .
cp -r resource/* .
- name: Use premake to generate make files
run: |
./premake5 gmake ${{ matrix.zip-support && '--server-zip-support' || '' }} \
${{ matrix.static-link && '--build-sqlite --build-event' || '' }}
- name: Make
run: |
cd build
make -j 4 config=release
cd ..
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: YGOPro-Server-${{ matrix.name }}
path: |
bin/release/ygopro
publish:
needs: [build-windows]
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
pattern: YGOPro-Server-windows-* # the "windows" (no hyphen) artifact is ignored
merge-multiple: true
- name: GitHub Release
uses: salix5/action-automatic-releases@node20
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "server-latest"
prerelease: true
title: "Development Build (Server Mode)"
files: |
x64/ygopro.exe
x64/AI.Server.exe
\ No newline at end of file
...@@ -14,14 +14,17 @@ mat_common: ...@@ -14,14 +14,17 @@ mat_common:
- linux - linux
script: script:
# lua # lua
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/lua-5.4.4.tar.gz | tar zfx - - wget -O - https://mat-cacher.moenext.com/https://www.lua.org/ftp/lua-5.4.8.tar.gz | tar zfx -
- mv lua-5.4.4 lua - mv lua-5.4.8 lua
# sqlite3 # sqlite3
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/sqlite-autoconf-3390300.tar.gz | tar zfx - - wget -O - https://mat-cacher.moenext.com/https://www.sqlite.org/2025/sqlite-autoconf-3500100.tar.gz | tar zfx -
- mv sqlite-autoconf-3390300 sqlite3 - mv sqlite-autoconf-3500100 sqlite3
# freetype # freetype
#- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/freetype-2.11.1.tar.gz | tar zfx - # - wget -O - https://mat-cacher.moenext.com/https://downloads.sourceforge.net/freetype/freetype-2.13.3.tar.gz | tar zfx -
#- mv freetype-2.11.1 freetype # - mv freetype-2.13.3 freetype
# event
- wget -O - https://mat-cacher.moenext.com/https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz | tar zfx -
- mv libevent-2.1.12-stable event
# irrlicht # irrlicht
- ./.ci/prepare-irrlicht.sh - ./.ci/prepare-irrlicht.sh
# miniaudio # miniaudio
...@@ -33,6 +36,7 @@ mat_common: ...@@ -33,6 +36,7 @@ mat_common:
- lua - lua
#- freetype #- freetype
- sqlite3 - sqlite3
- event
- irrlicht - irrlicht
#- miniaudio #- miniaudio
...@@ -68,7 +72,7 @@ mat_macos: ...@@ -68,7 +72,7 @@ mat_macos:
- linux - linux
script: script:
- apt update; apt -y install wget tar - apt update; apt -y install wget tar
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/premake-5.0.0-beta5-macosx.tar.gz | tar zfx - - wget -O - https://cdn02.moecube.com:444/premake5-built/premake-5.0.0-beta7-macosx.tar.gz | tar zfx -
- chmod +x premake5 - chmod +x premake5
artifacts: artifacts:
paths: paths:
...@@ -81,25 +85,21 @@ mat_windows: ...@@ -81,25 +85,21 @@ mat_windows:
script: script:
- apt update; apt -y install wget tar patch p7zip-full - apt update; apt -y install wget tar patch p7zip-full
# premake5.exe # premake5.exe
- wget https://cdn02.moecube.com:444/ygopro-build-materials/premake-5.0.0-beta5-windows.zip - wget https://cdn02.moecube.com:444/premake5-built/premake-5.0.0-beta7-windows.zip
- 7z x -y premake-5.0.0-beta5-windows.zip - 7z x -y premake-5.0.0-beta7-windows.zip
# event
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/libevent-2.0.22-stable.tar.gz | tar zfx -
- mv libevent-2.0.22-stable event
artifacts: artifacts:
paths: paths:
- premake5.exe - premake5.exe
- event
._exec_build: ._exec_build:
stage: build stage: build
#variables: #variables:
# NO_LUA_SAFE: '1' # on client no lua safe # NO_LUA_SAFE: '1' # on client no lua safe
cache: #cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" # key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths: # paths:
- bin/ # - bin/
- obj/ # - obj/
.exec_windows: .exec_windows:
extends: ._exec_build extends: ._exec_build
...@@ -119,19 +119,19 @@ exec_windows: ...@@ -119,19 +119,19 @@ exec_windows:
extends: .exec_windows extends: .exec_windows
script: script:
- '.\premake5.exe vs2019 --server-zip-support' - '.\premake5.exe vs2019 --server-zip-support'
- cmd /c '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" build\YGOPro.sln /m /p:Configuration=Release' - cmd /c '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" build\YGOPro.sln /m /p:Configuration=Release /p:Platform=x64'
- mkdir dist - mkdir dist
- mkdir dist\windows - mkdir dist\windows
- copy bin\release\ygopro.exe dist\windows\ygopro.exe - copy bin\release\x64\ygopro.exe dist\windows\ygopro.exe
exec_windows_pro3: exec_windows_pro3:
extends: .exec_windows extends: .exec_windows
script: script:
- '.\premake5.exe vs2019 --server-pro3-support --log-in-chat' - '.\premake5.exe vs2019 --server-pro3-support --log-in-chat'
- cmd /c '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" build\YGOPro.sln /m /p:Configuration=Release' - cmd /c '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" build\YGOPro.sln /m /p:Configuration=Release /p:Platform=x64'
- mkdir dist - mkdir dist
- mkdir dist\windows - mkdir dist\windows
- copy bin\release\ygoserver.dll dist\windows\ygoserver.dll - copy bin\release\x64\ygoserver.dll dist\windows\ygoserver.dll
.exec_unix_common: .exec_unix_common:
extends: ._exec_build extends: ._exec_build
...@@ -140,6 +140,7 @@ exec_windows_pro3: ...@@ -140,6 +140,7 @@ exec_windows_pro3:
TARGET_FILE: ygopro TARGET_FILE: ygopro
PREMAKE5_BIN: premake5 PREMAKE5_BIN: premake5
script: script:
- ./.ci/configure-libevent.sh
- $PREMAKE5_BIN gmake - $PREMAKE5_BIN gmake
- cd build - cd build
- make config=release -j$(nproc) - make config=release -j$(nproc)
...@@ -169,8 +170,6 @@ exec_windows_pro3: ...@@ -169,8 +170,6 @@ exec_windows_pro3:
variables: variables:
BUILD_SQLITE: '1' BUILD_SQLITE: '1'
SERVER_ZIP_SUPPORT: '1' SERVER_ZIP_SUPPORT: '1'
EVENT_INCLUDE_DIR: /usr/share/libevent-stable/include
EVENT_LIB_DIR: /usr/share/libevent-stable/lib
RELEASE_DIR: linux-x64 RELEASE_DIR: linux-x64
.exec_debian: .exec_debian:
...@@ -182,31 +181,35 @@ exec_windows_pro3: ...@@ -182,31 +181,35 @@ exec_windows_pro3:
- apt update; apt -y install git build-essential liblua5.4-dev libsqlite3-dev libevent-dev - apt update; apt -y install git build-essential liblua5.4-dev libsqlite3-dev libevent-dev
.use_arm: .use_arm:
image: git-registry.moenext.com/mycard/docker-ygopro-builder:fpic
tags: tags:
- arm - arm
.use_pro3: .use_pro3:
image: git-registry.moenext.com/mycard/docker-ygopro-builder:fpic
variables: variables:
SERVER_PRO3_SUPPORT: '1' SERVER_PRO3_SUPPORT: '1'
LOG_IN_CHAT: '1' LOG_IN_CHAT: '1'
.use_pro3_linux:
extends: .use_pro3
variables:
TARGET_FILE: libygoserver.so TARGET_FILE: libygoserver.so
.use_pro3_macos: .use_pro3_macos:
extends: .use_pro3
variables: variables:
SERVER_PRO3_SUPPORT: '1'
LOG_IN_CHAT: '1'
TARGET_FILE: libygoserver.dylib TARGET_FILE: libygoserver.dylib
LIBEVENT_PREBUILD_FLAGS: '-fPIC'
exec_linux: exec_linux:
extends: .exec_linux extends: .exec_linux
tags:
- noavx2
exec_linux_pro3: exec_linux_pro3:
extends: extends:
- .exec_linux - .exec_linux
- .use_pro3 - .use_pro3_linux
tags:
- avx2
exec_debian: exec_debian:
extends: .exec_debian extends: .exec_debian
...@@ -222,7 +225,7 @@ exec_linuxarm_pro3: ...@@ -222,7 +225,7 @@ exec_linuxarm_pro3:
extends: extends:
- .exec_linux - .exec_linux
- .use_arm - .use_arm
- .use_pro3 - .use_pro3_linux
variables: variables:
RELEASE_DIR: linux-arm64 RELEASE_DIR: linux-arm64
...@@ -240,14 +243,13 @@ exec_debianarm: ...@@ -240,14 +243,13 @@ exec_debianarm:
- mat_common - mat_common
- mat_macos - mat_macos
- mat_submodules - mat_submodules
before_script:
- env CFLAGS=$LIBEVENT_PREBUILD_FLAGS CXXFLAGS=$LIBEVENT_PREBUILD_FLAGS ./.ci/libevent-prebuild.sh
variables: variables:
PREMAKE5_BIN: ./premake5 PREMAKE5_BIN: ./premake5
BUILD_SQLITE: '1' BUILD_SQLITE: '1'
BUILD_EVENT: '1'
SERVER_ZIP_SUPPORT: '1' SERVER_ZIP_SUPPORT: '1'
EVENT_INCLUDE_DIR: ../libevent-stable/include before_script:
EVENT_LIB_DIR: ../libevent-stable/lib - rm -rf sqlite3/VERSION sqlite3/version
exec_macos_x64: exec_macos_x64:
extends: .exec_macos_platform extends: .exec_macos_platform
......
language: cpp
dist: bionic
git:
submodules: false
addons:
ssh_known_hosts:
- github.com
apt:
# sources:
# - ubuntu-toolchain-r-test
packages:
# - gcc-6
# - g++-6
- libevent-dev
- libsqlite3-dev
- liblua5.3-dev
env:
- DATABASE_FILE=cards.cdb
before_install:
- git submodule update --init --recursive
#- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
#- sudo ln -s /usr/bin/g++-6 /usr/local/bin/g++
#- g++ --version
- wget -O - https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-linux.tar.gz | tar zfx -
#- wget -O - https://www.lua.org/ftp/lua-5.3.6.tar.gz | tar zfx -; cd lua-5.3.6; sudo make linux install; cd ..
script:
- ./premake5 gmake
- cd build
- make config=release
- cd ..
- mv -f ./bin/release/ygopro .
- strip ygopro
- mkdir replay
- echo "select id from datas;" | sqlite3 $DATABASE_FILE | xargs -I {} ./ygopro {} 2>&1 | tee ./redtext.txt
- bash -c "exit $(cat ./redtext.txt | wc -l)"
version: '{build}' version: '{build}'
image: Visual Studio 2019 image: Visual Studio 2022
skip_tags: true skip_tags: true
...@@ -7,37 +7,37 @@ install: ...@@ -7,37 +7,37 @@ install:
- git submodule update --init --recursive - git submodule update --init --recursive
# environment and system dependency # environment and system dependency
- bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://github.com/premake/premake-core/releases/download/v5.0.0-beta5/premake-5.0.0-beta5-windows.zip ; exit 0" - bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://github.com/premake/premake-core/releases/download/v5.0.0-beta6/premake-5.0.0-beta6-windows.zip ; exit 0"
- 7z x premake-5.0.0-beta5-windows.zip - 7z x premake-5.0.0-beta6-windows.zip
- bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://github.com/libevent/libevent/releases/download/release-2.0.22-stable/libevent-2.0.22-stable.tar.gz ; exit 0" - bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz ; exit 0"
- tar xf libevent-2.0.22-stable.tar.gz - tar xf libevent-2.1.12-stable.tar.gz
- move libevent-2.0.22-stable event - move libevent-2.1.12-stable event
- xcopy /E event\WIN32-Code event\include
- bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://www.lua.org/ftp/lua-5.4.4.tar.gz ; exit 0" - bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://www.lua.org/ftp/lua-5.4.7.tar.gz ; exit 0"
- tar xf lua-5.4.4.tar.gz - tar xf lua-5.4.7.tar.gz
- move lua-5.4.4 lua - move lua-5.4.7 lua
- bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://www.sqlite.org/2024/sqlite-amalgamation-3470000.zip ; exit 0" - bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip ; exit 0"
- 7z x sqlite-amalgamation-3470000.zip - 7z x sqlite-amalgamation-3490100.zip
- move sqlite-amalgamation-3470000 sqlite3 - move sqlite-amalgamation-3490100 sqlite3
- git clone --depth=1 https://github.com/mercury233/irrlicht irrlicht - git clone --depth=1 https://github.com/mercury233/irrlicht
before_build: before_build:
- xcopy /E premake\* . - xcopy /E premake\* .
- xcopy /E resource\* . - xcopy /E resource\* .
- premake5 vs2019 --server-zip-support - premake5 vs2022
configuration: Release configuration: Release
platform: x64
build: build:
project: build/YGOPro.sln project: build/YGOPro.sln
parallel: true parallel: true
after_build: after_build:
- ps: move bin\release\ygopro.exe . - ps: move bin\release\x64\ygopro.exe .
# nodejs # nodejs
- bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://nodejs.org/dist/v16.9.1/node-v16.9.1-win-x64.7z ; exit 0" - bash -c "curl --retry 5 --connect-timeout 30 --location --remote-header-name --remote-name https://nodejs.org/dist/v16.9.1/node-v16.9.1-win-x64.7z ; exit 0"
...@@ -90,8 +90,7 @@ deploy: ...@@ -90,8 +90,7 @@ deploy:
branch: server branch: server
cache: cache:
- premake-5.0.0-beta2-windows.zip - premake-5.0.0-beta6-windows.zip
- libevent-2.0.22-stable.tar.gz - libevent-2.1.12-stable.tar.gz
- irrlicht-1.8.5.zip - lua-5.4.7.tar.gz
- lua-5.4.4.tar.gz - sqlite-amalgamation-3490100.zip
- sqlite-amalgamation-3390300.zip
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
john@suckerfreegames.com john@suckerfreegames.com
*/ */
#define _IRR_STATIC_LIB_
#include <irrlicht.h> #include <irrlicht.h>
#include "CGUITTFont.h" #include "CGUITTFont.h"
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "image_manager.h" #include "image_manager.h"
#include "game.h" #include "game.h"
#include "materials.h" #include "materials.h"
#include "../ocgcore/common.h"
namespace ygo { namespace ygo {
...@@ -15,7 +14,7 @@ ClientField::ClientField() { ...@@ -15,7 +14,7 @@ ClientField::ClientField() {
mzone[p].resize(7, 0); mzone[p].resize(7, 0);
szone[p].resize(8, 0); szone[p].resize(8, 0);
} }
rnd.reset((uint_fast32_t)std::random_device()()); rnd.seed(std::random_device()());
} }
ClientField::~ClientField() { ClientField::~ClientField() {
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
...@@ -229,12 +228,12 @@ void ClientField::AddCard(ClientCard* pcard, int controler, int location, int se ...@@ -229,12 +228,12 @@ void ClientField::AddCard(ClientCard* pcard, int controler, int location, int se
} }
case LOCATION_GRAVE: { case LOCATION_GRAVE: {
grave[controler].push_back(pcard); grave[controler].push_back(pcard);
ResetSequence(grave[controler], false); pcard->sequence = (unsigned char)(grave[controler].size() - 1);
break; break;
} }
case LOCATION_REMOVED: { case LOCATION_REMOVED: {
remove[controler].push_back(pcard); remove[controler].push_back(pcard);
ResetSequence(remove[controler], false); pcard->sequence = (unsigned char)(remove[controler].size() - 1);
break; break;
} }
case LOCATION_EXTRA: { case LOCATION_EXTRA: {
...@@ -257,8 +256,13 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) { ...@@ -257,8 +256,13 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) {
switch (location) { switch (location) {
case LOCATION_DECK: { case LOCATION_DECK: {
pcard = deck[controler][sequence]; pcard = deck[controler][sequence];
deck[controler].erase(deck[controler].begin() + sequence); for (size_t i = sequence; i < deck[controler].size() - 1; ++i) {
ResetSequence(deck[controler], true); deck[controler][i] = deck[controler][i + 1];
deck[controler][i]->sequence--;
deck[controler][i]->curPos -= irr::core::vector3df(0, 0, 0.01f);
deck[controler][i]->mTransform.setTranslation(deck[controler][i]->curPos);
}
deck[controler].erase(deck[controler].end() - 1);
break; break;
} }
case LOCATION_HAND: { case LOCATION_HAND: {
...@@ -279,20 +283,35 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) { ...@@ -279,20 +283,35 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) {
} }
case LOCATION_GRAVE: { case LOCATION_GRAVE: {
pcard = grave[controler][sequence]; pcard = grave[controler][sequence];
grave[controler].erase(grave[controler].begin() + sequence); for (size_t i = sequence; i < grave[controler].size() - 1; ++i) {
ResetSequence(grave[controler], true); grave[controler][i] = grave[controler][i + 1];
grave[controler][i]->sequence--;
grave[controler][i]->curPos -= irr::core::vector3df(0, 0, 0.01f);
grave[controler][i]->mTransform.setTranslation(grave[controler][i]->curPos);
}
grave[controler].erase(grave[controler].end() - 1);
break; break;
} }
case LOCATION_REMOVED: { case LOCATION_REMOVED: {
pcard = remove[controler][sequence]; pcard = remove[controler][sequence];
remove[controler].erase(remove[controler].begin() + sequence); for (size_t i = sequence; i < remove[controler].size() - 1; ++i) {
ResetSequence(remove[controler], true); remove[controler][i] = remove[controler][i + 1];
remove[controler][i]->sequence--;
remove[controler][i]->curPos -= irr::core::vector3df(0, 0, 0.01f);
remove[controler][i]->mTransform.setTranslation(remove[controler][i]->curPos);
}
remove[controler].erase(remove[controler].end() - 1);
break; break;
} }
case LOCATION_EXTRA: { case LOCATION_EXTRA: {
pcard = extra[controler][sequence]; pcard = extra[controler][sequence];
extra[controler].erase(extra[controler].begin() + sequence); for (size_t i = sequence; i < extra[controler].size() - 1; ++i) {
ResetSequence(extra[controler], true); extra[controler][i] = extra[controler][i + 1];
extra[controler][i]->sequence--;
extra[controler][i]->curPos -= irr::core::vector3df(0, 0, 0.01f);
extra[controler][i]->mTransform.setTranslation(extra[controler][i]->curPos);
}
extra[controler].erase(extra[controler].end() - 1);
if (pcard->position & POS_FACEUP) if (pcard->position & POS_FACEUP)
extra_p_count[controler]--; extra_p_count[controler]--;
break; break;
...@@ -418,7 +437,7 @@ void ClientField::ShowSelectCard(bool buttonok, bool chain) { ...@@ -418,7 +437,7 @@ void ClientField::ShowSelectCard(bool buttonok, bool chain) {
} }
} }
if(has_card_in_grave) { if(has_card_in_grave) {
rnd.shuffle_vector(selectable_cards); std::shuffle(selectable_cards.begin(), selectable_cards.end(), rnd);
} }
} }
int startpos; int startpos;
...@@ -1163,6 +1182,14 @@ bool ClientField::ShowSelectSum(bool panelmode) { ...@@ -1163,6 +1182,14 @@ bool ClientField::ShowSelectSum(bool panelmode) {
} }
return false; return false;
} }
static void get_sum_params(irr::u32 opParam, int& op1, int& op2) {
op1 = opParam & 0xffff;
op2 = (opParam >> 16) & 0xffff;
if(op2 & 0x8000) {
op1 = opParam & 0x7fffffff;
op2 = 0;
}
}
bool ClientField::CheckSelectSum() { bool ClientField::CheckSelectSum() {
std::set<ClientCard*> selable; std::set<ClientCard*> selable;
for(auto sc : selectsum_all) { for(auto sc : selectsum_all) {
...@@ -1203,8 +1230,8 @@ bool ClientField::CheckSelectSum() { ...@@ -1203,8 +1230,8 @@ bool ClientField::CheckSelectSum() {
int mm = -1, mx = -1, max = 0, sumc = 0; int mm = -1, mx = -1, max = 0, sumc = 0;
bool ret = false; bool ret = false;
for (auto sc : selected_cards) { for (auto sc : selected_cards) {
int op1 = sc->opParam & 0xffff; int op1, op2;
int op2 = sc->opParam >> 16; get_sum_params(sc->opParam, op1, op2);
int opmin = (op2 > 0 && op1 > op2) ? op2 : op1; int opmin = (op2 > 0 && op1 > op2) ? op2 : op1;
int opmax = op2 > op1 ? op2 : op1; int opmax = op2 > op1 ? op2 : op1;
if (mm == -1 || opmin < mm) if (mm == -1 || opmin < mm)
...@@ -1219,8 +1246,8 @@ bool ClientField::CheckSelectSum() { ...@@ -1219,8 +1246,8 @@ bool ClientField::CheckSelectSum() {
if (select_sumval <= max && select_sumval > max - mx) if (select_sumval <= max && select_sumval > max - mx)
ret = true; ret = true;
for(auto sc : selable) { for(auto sc : selable) {
int op1 = sc->opParam & 0xffff; int op1, op2;
int op2 = sc->opParam >> 16; get_sum_params(sc->opParam, op1, op2);
int m = op1; int m = op1;
int sums = sumc; int sums = sumc;
sums += m; sums += m;
...@@ -1286,11 +1313,19 @@ bool ClientField::CheckSelectTribute() { ...@@ -1286,11 +1313,19 @@ bool ClientField::CheckSelectTribute() {
} }
return ret; return ret;
} }
void ClientField::get_sum_params(unsigned int opParam, int& op1, int& op2) {
op1 = opParam & 0xffff;
op2 = (opParam >> 16) & 0xffff;
if (op2 & 0x8000) {
op1 = opParam & 0x7fffffff;
op2 = 0;
}
}
bool ClientField::check_min(const std::set<ClientCard*>& left, std::set<ClientCard*>::const_iterator index, int min, int max) { bool ClientField::check_min(const std::set<ClientCard*>& left, std::set<ClientCard*>::const_iterator index, int min, int max) {
if (index == left.end()) if (index == left.end())
return false; return false;
int op1 = (*index)->opParam & 0xffff; int op1, op2;
int op2 = (*index)->opParam >> 16; get_sum_params((*index)->opParam, op1, op2);
int m = (op2 > 0 && op1 > op2) ? op2 : op1; int m = (op2 > 0 && op1 > op2) ? op2 : op1;
if (m >= min && m <= max) if (m >= min && m <= max)
return true; return true;
...@@ -1309,9 +1344,8 @@ bool ClientField::check_sel_sum_s(const std::set<ClientCard*>& left, int index, ...@@ -1309,9 +1344,8 @@ bool ClientField::check_sel_sum_s(const std::set<ClientCard*>& left, int index,
check_sel_sum_t(left, acc); check_sel_sum_t(left, acc);
return false; return false;
} }
int l = selected_cards[index]->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params(selected_cards[index]->opParam, l1, l2);
int l2 = l >> 16;
bool res1 = false, res2 = false; bool res1 = false, res2 = false;
res1 = check_sel_sum_s(left, index + 1, acc - l1); res1 = check_sel_sum_s(left, index + 1, acc - l1);
if (l2 > 0) if (l2 > 0)
...@@ -1325,9 +1359,8 @@ void ClientField::check_sel_sum_t(const std::set<ClientCard*>& left, int acc) { ...@@ -1325,9 +1359,8 @@ void ClientField::check_sel_sum_t(const std::set<ClientCard*>& left, int acc) {
continue; continue;
std::set<ClientCard*> testlist(left); std::set<ClientCard*> testlist(left);
testlist.erase(*sit); testlist.erase(*sit);
int l = (*sit)->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params((*sit)->opParam, l1, l2);
int l2 = l >> 16;
if (check_sum(testlist.begin(), testlist.end(), acc - l1, count) if (check_sum(testlist.begin(), testlist.end(), acc - l1, count)
|| (l2 > 0 && check_sum(testlist.begin(), testlist.end(), acc - l2, count))) { || (l2 > 0 && check_sum(testlist.begin(), testlist.end(), acc - l2, count))) {
selectsum_cards.insert(*sit); selectsum_cards.insert(*sit);
...@@ -1339,9 +1372,8 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se ...@@ -1339,9 +1372,8 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se
return count >= select_min && count <= select_max; return count >= select_min && count <= select_max;
if (acc < 0 || index == end) if (acc < 0 || index == end)
return false; return false;
int l = (*index)->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params((*index)->opParam, l1, l2);
int l2 = l >> 16;
if ((l1 == acc || (l2 > 0 && l2 == acc)) && (count + 1 >= select_min) && (count + 1 <= select_max)) if ((l1 == acc || (l2 > 0 && l2 == acc)) && (count + 1 >= select_min) && (count + 1 <= select_max))
return true; return true;
++index; ++index;
...@@ -1356,9 +1388,8 @@ bool ClientField::check_sel_sum_trib_s(const std::set<ClientCard*>& left, int in ...@@ -1356,9 +1388,8 @@ bool ClientField::check_sel_sum_trib_s(const std::set<ClientCard*>& left, int in
check_sel_sum_trib_t(left, acc); check_sel_sum_trib_t(left, acc);
return acc >= select_min && acc <= select_max; return acc >= select_min && acc <= select_max;
} }
int l = selected_cards[index]->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params(selected_cards[index]->opParam, l1, l2);
int l2 = l >> 16;
bool res1 = false, res2 = false; bool res1 = false, res2 = false;
res1 = check_sel_sum_trib_s(left, index + 1, acc + l1); res1 = check_sel_sum_trib_s(left, index + 1, acc + l1);
if(l2 > 0) if(l2 > 0)
...@@ -1371,9 +1402,8 @@ void ClientField::check_sel_sum_trib_t(const std::set<ClientCard*>& left, int ac ...@@ -1371,9 +1402,8 @@ void ClientField::check_sel_sum_trib_t(const std::set<ClientCard*>& left, int ac
continue; continue;
std::set<ClientCard*> testlist(left); std::set<ClientCard*> testlist(left);
testlist.erase(*sit); testlist.erase(*sit);
int l = (*sit)->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params((*sit)->opParam, l1, l2);
int l2 = l >> 16;
if(check_sum_trib(testlist.begin(), testlist.end(), acc + l1) if(check_sum_trib(testlist.begin(), testlist.end(), acc + l1)
|| (l2 > 0 && check_sum_trib(testlist.begin(), testlist.end(), acc + l2))) { || (l2 > 0 && check_sum_trib(testlist.begin(), testlist.end(), acc + l2))) {
selectsum_cards.insert(*sit); selectsum_cards.insert(*sit);
...@@ -1385,9 +1415,8 @@ bool ClientField::check_sum_trib(std::set<ClientCard*>::const_iterator index, st ...@@ -1385,9 +1415,8 @@ bool ClientField::check_sum_trib(std::set<ClientCard*>::const_iterator index, st
return true; return true;
if(acc > select_max || index == end) if(acc > select_max || index == end)
return false; return false;
int l = (*index)->opParam; int l1, l2;
int l1 = l & 0xffff; get_sum_params((*index)->opParam, l1, l2);
int l2 = l >> 16;
if((acc + l1 >= select_min && acc + l1 <= select_max) || (acc + l2 >= select_min && acc + l2 <= select_max)) if((acc + l1 >= select_min && acc + l1 <= select_max) || (acc + l2 >= select_min && acc + l2 <= select_max))
return true; return true;
++index; ++index;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define CLIENT_FIELD_H #define CLIENT_FIELD_H
#include "config.h" #include "config.h"
#include "../ocgcore/mtrandom.h" #include <random>
#include <vector> #include <vector>
#include <set> #include <set>
#include <map> #include <map>
...@@ -92,7 +92,7 @@ public: ...@@ -92,7 +92,7 @@ public:
bool cant_check_grave{ false }; bool cant_check_grave{ false };
bool tag_surrender{ false }; bool tag_surrender{ false };
bool tag_teammate_surrender{ false }; bool tag_teammate_surrender{ false };
mt19937 rnd; std::mt19937 rnd;
ClientField(); ClientField();
~ClientField(); ~ClientField();
...@@ -121,6 +121,7 @@ public: ...@@ -121,6 +121,7 @@ public:
bool ShowSelectSum(bool panelmode); bool ShowSelectSum(bool panelmode);
bool CheckSelectSum(); bool CheckSelectSum();
bool CheckSelectTribute(); bool CheckSelectTribute();
void get_sum_params(unsigned int opParam, int& op1, int& op2);
bool check_min(const std::set<ClientCard*>& left, std::set<ClientCard*>::const_iterator index, int min, int max); bool check_min(const std::set<ClientCard*>& left, std::set<ClientCard*>::const_iterator index, int min, int max);
bool check_sel_sum_s(const std::set<ClientCard*>& left, int index, int acc); bool check_sel_sum_s(const std::set<ClientCard*>& left, int index, int acc);
void check_sel_sum_t(const std::set<ClientCard*>& left, int acc); void check_sel_sum_t(const std::set<ClientCard*>& left, int acc);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <windows.h> #include <windows.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#ifdef _MSC_VER #if defined(_MSC_VER) or defined(__MINGW32__)
#define mywcsncasecmp _wcsnicmp #define mywcsncasecmp _wcsnicmp
#define mystrncasecmp _strnicmp #define mystrncasecmp _strnicmp
#else #else
...@@ -52,6 +52,17 @@ inline int _wtoi(const wchar_t * str){ ...@@ -52,6 +52,17 @@ inline int _wtoi(const wchar_t * str){
} }
#endif #endif
// load env things
#ifdef _WIN32
#include <windows.h>
#include <string>
#else
#include <unistd.h>
#include <stdlib.h>
extern char** environ;
#endif
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
...@@ -105,5 +116,7 @@ extern bool auto_watch_mode; ...@@ -105,5 +116,7 @@ extern bool auto_watch_mode;
extern bool open_file; extern bool open_file;
extern wchar_t open_file_name[256]; extern wchar_t open_file_name[256];
extern bool bot_mode; extern bool bot_mode;
extern bool expansions_specified;
extern std::vector<std::wstring> expansions_list;
#endif #endif
...@@ -103,12 +103,16 @@ bool DataManager::LoadDB(const wchar_t* wfile) { ...@@ -103,12 +103,16 @@ bool DataManager::LoadDB(const wchar_t* wfile) {
else else
ret = ReadDB(pDB); ret = ReadDB(pDB);
sqlite3_close(pDB); sqlite3_close(pDB);
return ret;
#else #else
#ifdef _WIN32 #ifdef _WIN32
auto reader = FileSystem->createAndOpenFile(wfile); auto reader = FileSystem->createAndOpenFile(wfile);
#else #else
auto reader = FileSystem->createAndOpenFile(file); auto reader = FileSystem->createAndOpenFile(file);
#endif #endif
return LoadDB(reader);
}
bool DataManager::LoadDB(irr::io::IReadFile* reader) {
if(reader == nullptr) if(reader == nullptr)
return false; return false;
spmemvfs_db_t db; spmemvfs_db_t db;
...@@ -120,14 +124,14 @@ bool DataManager::LoadDB(const wchar_t* wfile) { ...@@ -120,14 +124,14 @@ bool DataManager::LoadDB(const wchar_t* wfile) {
reader->drop(); reader->drop();
(mem->data)[mem->total] = '\0'; (mem->data)[mem->total] = '\0';
bool ret{}; bool ret{};
if (spmemvfs_open_db(&db, file, mem) != SQLITE_OK) if (spmemvfs_open_db(&db, "temp.db", mem) != SQLITE_OK)
ret = Error(db.handle); ret = Error(db.handle);
else else
ret = ReadDB(db.handle); ret = ReadDB(db.handle);
spmemvfs_close_db(&db); spmemvfs_close_db(&db);
spmemvfs_env_fini(); spmemvfs_env_fini();
#endif //YGOPRO_SERVER_MODE
return ret; return ret;
#endif //SERVER_ZIP_SUPPORT
} }
#ifndef YGOPRO_SERVER_MODE #ifndef YGOPRO_SERVER_MODE
bool DataManager::LoadStrings(const char* file) { bool DataManager::LoadStrings(const char* file) {
...@@ -141,6 +145,17 @@ bool DataManager::LoadStrings(const char* file) { ...@@ -141,6 +145,17 @@ bool DataManager::LoadStrings(const char* file) {
std::fclose(fp); std::fclose(fp);
return true; return true;
} }
bool DataManager::LoadStrings(const wchar_t* file) {
FILE* fp = mywfopen(file, "r");
if(!fp)
return false;
char linebuf[TEXT_LINE_SIZE]{};
while(std::fgets(linebuf, sizeof linebuf, fp)) {
ReadStringConfLine(linebuf);
}
std::fclose(fp);
return true;
}
bool DataManager::LoadStrings(irr::io::IReadFile* reader) { bool DataManager::LoadStrings(irr::io::IReadFile* reader) {
char ch{}; char ch{};
std::string linebuf; std::string linebuf;
...@@ -187,10 +202,162 @@ void DataManager::ReadStringConfLine(const char* linebuf) { ...@@ -187,10 +202,162 @@ void DataManager::ReadStringConfLine(const char* linebuf) {
_setnameStrings[value] = strBuffer; _setnameStrings[value] = strBuffer;
} }
} }
bool DataManager::LoadServerList(const char* file) {
FILE* fp = myfopen(file, "r");
if(!fp)
return false;
char linebuf[TEXT_LINE_SIZE]{};
while(std::fgets(linebuf, sizeof linebuf, fp)) {
ReadServerConfLine(linebuf);
}
std::fclose(fp);
return true;
}
bool DataManager::LoadServerList(const wchar_t* file) {
FILE* fp = mywfopen(file, "r");
if(!fp)
return false;
char linebuf[TEXT_LINE_SIZE]{};
while(std::fgets(linebuf, sizeof linebuf, fp)) {
ReadServerConfLine(linebuf);
}
std::fclose(fp);
return true;
}
bool DataManager::LoadServerList(irr::io::IReadFile* reader) {
char ch{};
std::string linebuf;
while (reader->read(&ch, 1)) {
if (ch == '\0')
break;
linebuf.push_back(ch);
if (ch == '\n' || linebuf.size() >= TEXT_LINE_SIZE - 1) {
ReadServerConfLine(linebuf.data());
linebuf.clear();
}
}
reader->drop();
return true;
}
void DataManager::ReadServerConfLine(const char* linebuf) {
char buffer[1024];
std::strncpy(buffer, linebuf, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
buffer[strcspn(buffer, "\n")] = '\0';
char* sep1 = std::strchr(buffer, '|');
if (sep1 != nullptr) {
*sep1 = '\0';
char* addrPart = sep1 + 1;
wchar_t wname[256], wip[512];
// read the server name
BufferIO::DecodeUTF8(buffer, wname);
// replace the first '|' with ':'
char* sep2 = std::strchr(addrPart, '|');
if (sep2) {
*sep2 = ':';
}
BufferIO::DecodeUTF8(addrPart, wip);
_serverStrings.emplace_back(wname, wip);
}
}
bool DataManager::LoadCorresSrvIni(const char* file) {
FILE* fp = myfopen(file, "r");
if(!fp)
return false;
char linebuf[TEXT_LINE_SIZE]{};
while(std::fgets(linebuf, sizeof linebuf, fp)) {
ReadCorresSrvIniLine(linebuf);
}
std::fclose(fp);
InsertServerList();
return true;
}
bool DataManager::LoadCorresSrvIni(const wchar_t* file) {
FILE* fp = mywfopen(file, "r");
if(!fp)
return false;
char linebuf[TEXT_LINE_SIZE]{};
while(std::fgets(linebuf, sizeof linebuf, fp)) {
ReadCorresSrvIniLine(linebuf);
}
std::fclose(fp);
InsertServerList();
return true;
}
bool DataManager::LoadCorresSrvIni(irr::io::IReadFile* reader) {
char ch{};
std::string linebuf;
while (reader->read(&ch, 1)) {
if (ch == '\0')
break;
linebuf.push_back(ch);
if (ch == '\n' || linebuf.size() >= TEXT_LINE_SIZE - 1) {
ReadCorresSrvIniLine(linebuf.data());
linebuf.clear();
}
}
reader->drop();
InsertServerList();
return true;
}
void DataManager::ReadCorresSrvIniLine(const char* linebuf) {
std::wstring name = GetINIValue(linebuf, "ServerName = ");
std::wstring host = GetINIValue(linebuf, "ServerHost = ");
std::wstring port = GetINIValue(linebuf, "ServerPort = ");
if (name != L"")
iniName = name;
if (host != L"")
iniHost = host;
if (port != L"")
iniPort = port;
}
std::wstring DataManager::GetINIValue(const char* line, const char* key) {
if (!line || !key) {
return L"";
}
const char* keyPos = strstr(line, key);
if (!keyPos) {
return L"";
}
const char* valStart = keyPos + strlen(key);
while (*valStart == ' ')
valStart++;
const char* valEnd = valStart;
while (*valEnd && *valEnd != '\n' && *valEnd != '\r')
valEnd++;
if (valStart == valEnd)
return L"";
std::string narrowStr(valStart, valEnd);
if (narrowStr.empty())
return L"";
wchar_t wbuf[1024];
BufferIO::DecodeUTF8(narrowStr.c_str(), wbuf);
return wbuf;
}
void DataManager::InsertServerList() {
if (iniName != L"" && iniHost != L"") {
std::wstring ip = iniHost;
if (iniPort != L"") {
ip += L":";
ip += iniPort;
}
_serverStrings.emplace_back(iniName, ip);
}
iniName.clear();
iniHost.clear();
iniPort.clear();
}
#endif //YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
bool DataManager::Error(sqlite3* pDB, sqlite3_stmt* pStmt) { bool DataManager::Error(sqlite3* pDB, sqlite3_stmt* pStmt) {
errmsg[0] = '\0'; std::snprintf(errmsg, sizeof errmsg, "%s", sqlite3_errmsg(pDB));
std::strncat(errmsg, sqlite3_errmsg(pDB), sizeof errmsg - 1);
if(pStmt) if(pStmt)
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
return false; return false;
...@@ -435,19 +602,14 @@ unsigned char* DataManager::ScriptReaderEx(const char* script_name, int* slen) { ...@@ -435,19 +602,14 @@ unsigned char* DataManager::ScriptReaderEx(const char* script_name, int* slen) {
buffer = ScriptReaderExSingle("specials/", script_name, slen, 9); buffer = ScriptReaderExSingle("specials/", script_name, slen, 9);
if(buffer) if(buffer)
return buffer; return buffer;
buffer = ScriptReaderExSingle("expansions/", script_name, slen); for(auto ex : mainGame->GetExpansionsListU("/")) {
if(buffer) buffer = ScriptReaderExSingle(ex.c_str(), script_name, slen);
return buffer; if(buffer)
#if defined(SERVER_PRO3_SUPPORT) && !defined(_WIN32) return buffer;
buffer = ScriptReaderExSingle("Expansions/", script_name, slen); }
if(buffer)
return buffer;
#endif
#if !defined(YGOPRO_SERVER_MODE) || defined(SERVER_ZIP_SUPPORT)
buffer = ScriptReaderExSingle("", script_name, slen, 2, TRUE); buffer = ScriptReaderExSingle("", script_name, slen, 2, TRUE);
if(buffer) if(buffer)
return buffer; return buffer;
#endif
return ScriptReaderExSingle("", script_name, slen); return ScriptReaderExSingle("", script_name, slen);
} }
unsigned char* DataManager::ScriptReaderExSingle(const char* path, const char* script_name, int* slen, int pre_len, unsigned int use_irr) { unsigned char* DataManager::ScriptReaderExSingle(const char* path, const char* script_name, int* slen, int pre_len, unsigned int use_irr) {
......
...@@ -45,10 +45,24 @@ public: ...@@ -45,10 +45,24 @@ public:
DataManager(); DataManager();
bool ReadDB(sqlite3* pDB); bool ReadDB(sqlite3* pDB);
bool LoadDB(const wchar_t* wfile); bool LoadDB(const wchar_t* wfile);
#if defined(SERVER_ZIP_SUPPORT) || !defined(YGOPRO_SERVER_MODE)
bool LoadDB(irr::io::IReadFile* reader);
#endif
#ifndef YGOPRO_SERVER_MODE #ifndef YGOPRO_SERVER_MODE
bool LoadStrings(const char* file); bool LoadStrings(const char* file);
bool LoadStrings(const wchar_t* file);
bool LoadStrings(irr::io::IReadFile* reader); bool LoadStrings(irr::io::IReadFile* reader);
void ReadStringConfLine(const char* linebuf); void ReadStringConfLine(const char* linebuf);
bool LoadServerList(const char* file);
bool LoadServerList(const wchar_t* file);
bool LoadServerList(irr::io::IReadFile* reader);
void ReadServerConfLine(const char* linebuf);
bool LoadCorresSrvIni(const char* file);
bool LoadCorresSrvIni(const wchar_t* file);
bool LoadCorresSrvIni(irr::io::IReadFile* reader);
void ReadCorresSrvIniLine(const char* linebuf);
std::wstring GetINIValue(const char* line, const char* key);
void InsertServerList();
#endif #endif
bool Error(sqlite3* pDB, sqlite3_stmt* pStmt = nullptr); bool Error(sqlite3* pDB, sqlite3_stmt* pStmt = nullptr);
...@@ -83,6 +97,7 @@ public: ...@@ -83,6 +97,7 @@ public:
std::unordered_map<unsigned int, std::wstring> _victoryStrings; std::unordered_map<unsigned int, std::wstring> _victoryStrings;
std::unordered_map<unsigned int, std::wstring> _setnameStrings; std::unordered_map<unsigned int, std::wstring> _setnameStrings;
std::unordered_map<unsigned int, std::wstring> _sysStrings; std::unordered_map<unsigned int, std::wstring> _sysStrings;
std::vector<std::pair<std::wstring, std::wstring>> _serverStrings;
#endif #endif
char errmsg[512]{}; char errmsg[512]{};
...@@ -119,6 +134,9 @@ private: ...@@ -119,6 +134,9 @@ private:
std::unordered_map<unsigned int, CardDataC> _datas; std::unordered_map<unsigned int, CardDataC> _datas;
std::unordered_map<unsigned int, CardString> _strings; std::unordered_map<unsigned int, CardString> _strings;
std::unordered_map<unsigned int, std::vector<uint16_t>> extra_setcode; std::unordered_map<unsigned int, std::vector<uint16_t>> extra_setcode;
std::wstring iniName;
std::wstring iniHost;
std::wstring iniPort;
}; };
extern DataManager dataManager; extern DataManager dataManager;
......
#include <array>
#include "config.h" #include "config.h"
#include "deck_con.h" #include "deck_con.h"
#include "myfilesystem.h" #include "myfilesystem.h"
#include "data_manager.h"
#include "deck_manager.h"
#include "image_manager.h" #include "image_manager.h"
#include "sound_manager.h" #include "sound_manager.h"
#include "game.h" #include "game.h"
...@@ -54,6 +53,14 @@ static inline void load_current_deck(irr::gui::IGUIComboBox* cbCategory, irr::gu ...@@ -54,6 +53,14 @@ static inline void load_current_deck(irr::gui::IGUIComboBox* cbCategory, irr::gu
deckManager.LoadCurrentDeck(cbCategory->getSelected(), cbCategory->getText(), cbDeck->getText()); deckManager.LoadCurrentDeck(cbCategory->getSelected(), cbCategory->getText(), cbDeck->getText());
} }
DeckBuilder::DeckBuilder() {
std::random_device rd;
std::array<uint32_t, 8> seed{};
for (auto& x : seed)
x = rd();
std::seed_seq seq(seed.begin(), seed.end());
rnd.seed(seq);
}
void DeckBuilder::Initialize() { void DeckBuilder::Initialize() {
mainGame->is_building = true; mainGame->is_building = true;
mainGame->is_siding = false; mainGame->is_siding = false;
...@@ -82,7 +89,6 @@ void DeckBuilder::Initialize() { ...@@ -82,7 +89,6 @@ void DeckBuilder::Initialize() {
filterList = &deckManager._lfList.back(); filterList = &deckManager._lfList.back();
} }
ClearSearch(); ClearSearch();
rnd.reset((uint_fast32_t)std::time(nullptr));
mouse_pos.set(0, 0); mouse_pos.set(0, 0);
hovered_code = 0; hovered_code = 0;
hovered_pos = 0; hovered_pos = 0;
...@@ -176,7 +182,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -176,7 +182,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break; break;
} }
case BUTTON_SHUFFLE_DECK: { case BUTTON_SHUFFLE_DECK: {
rnd.shuffle_vector(deckManager.current_deck.main); std::shuffle(deckManager.current_deck.main.begin(), deckManager.current_deck.main.end(), rnd);
break; break;
} }
case BUTTON_SAVE_DECK: { case BUTTON_SAVE_DECK: {
...@@ -432,6 +438,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -432,6 +438,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
prev_operation = id; prev_operation = id;
break; break;
} }
case BUTTON_IMPORT_DECK_CODE: {
time_t nowtime = std::time(nullptr);
wchar_t timetext[40];
std::wcsftime(timetext, sizeof timetext / sizeof timetext[0], L"%Y-%m-%d %H-%M-%S", std::localtime(&nowtime));
mainGame->gMutex.lock();
mainGame->stDMMessage->setText(dataManager.GetSysString(1471));
mainGame->ebDMName->setVisible(true);
mainGame->ebDMName->setText(timetext);
mainGame->PopupElement(mainGame->wDMQuery);
mainGame->gMutex.unlock();
prev_operation = id;
break;
}
case BUTTON_EXPORT_DECK_CODE: {
std::stringstream textStream;
deckManager.SaveDeck(deckManager.current_deck, textStream);
wchar_t text[0x10000];
BufferIO::DecodeUTF8(textStream.str().c_str(), text);
mainGame->env->getOSOperator()->copyToClipboard(text);
mainGame->stACMessage->setText(dataManager.GetSysString(1480));
mainGame->PopupElement(mainGame->wACMessage, 20);
break;
}
case BUTTON_DM_OK: { case BUTTON_DM_OK: {
switch(prev_operation) { switch(prev_operation) {
case BUTTON_NEW_CATEGORY: { case BUTTON_NEW_CATEGORY: {
...@@ -508,7 +537,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -508,7 +537,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
} }
break; break;
} }
case BUTTON_NEW_DECK: { case BUTTON_NEW_DECK:
case BUTTON_IMPORT_DECK_CODE: {
const wchar_t* deckname = mainGame->ebDMName->getText(); const wchar_t* deckname = mainGame->ebDMName->getText();
wchar_t catepath[256]; wchar_t catepath[256];
DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText()); DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText());
...@@ -516,9 +546,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) { ...@@ -516,9 +546,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname); myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname);
bool res = false; bool res = false;
if(!FileSystem::IsFileExists(filepath)) { if(!FileSystem::IsFileExists(filepath)) {
deckManager.current_deck.main.clear(); if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.extra.clear(); deckManager.current_deck.main.clear();
deckManager.current_deck.side.clear(); deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
} else {
const wchar_t* txt = mainGame->env->getOSOperator()->getTextFromClipboard();
if(txt) {
char text[0x10000];
BufferIO::EncodeUTF8(txt, text);
std::istringstream textStream(text);
deckManager.LoadCurrentDeck(textStream);
}
}
res = DeckManager::SaveDeck(deckManager.current_deck, filepath); res = DeckManager::SaveDeck(deckManager.current_deck, filepath);
RefreshDeckList(); RefreshDeckList();
ChangeCategory(mainGame->lstCategories->getSelected()); ChangeCategory(mainGame->lstCategories->getSelected());
......
...@@ -3,15 +3,16 @@ ...@@ -3,15 +3,16 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <random>
#include <irrlicht.h> #include <irrlicht.h>
#include "data_manager.h" #include "data_manager.h"
#include "deck_manager.h" #include "deck_manager.h"
#include "../ocgcore/mtrandom.h"
namespace ygo { namespace ygo {
class DeckBuilder: public irr::IEventReceiver { class DeckBuilder: public irr::IEventReceiver {
public: public:
DeckBuilder();
bool OnEvent(const irr::SEvent& event) override; bool OnEvent(const irr::SEvent& event) override;
void Initialize(); void Initialize();
void Terminate(); void Terminate();
...@@ -80,7 +81,7 @@ public: ...@@ -80,7 +81,7 @@ public:
bool is_modified{}; bool is_modified{};
bool readonly{}; bool readonly{};
bool showing_pack{}; bool showing_pack{};
mt19937 rnd; std::mt19937 rnd;
const LFList* filterList{}; const LFList* filterList{};
std::vector<code_pointer> results; std::vector<code_pointer> results;
......
...@@ -11,53 +11,49 @@ char DeckManager::deckBuffer[0x10000]{}; ...@@ -11,53 +11,49 @@ char DeckManager::deckBuffer[0x10000]{};
#endif #endif
DeckManager deckManager; DeckManager deckManager;
void DeckManager::LoadLFListSingle(const char* path) { void DeckManager::LoadLFListSingle(const char* path, bool insert) {
auto cur = _lfList.rend();
FILE* fp = myfopen(path, "r"); FILE* fp = myfopen(path, "r");
char linebuf[256]{}; if (!fp) return;
wchar_t strBuffer[256]{}; _LoadLFListFromLineProvider([&](char* buf, size_t sz) {
char str1[16]{}; return std::fgets(buf, sz, fp) != nullptr;
if(fp) { }, insert);
while(std::fgets(linebuf, sizeof linebuf, fp)) { std::fclose(fp);
if(linebuf[0] == '#') }
continue; void DeckManager::LoadLFListSingle(const wchar_t* path, bool insert) {
if(linebuf[0] == '!') { FILE* fp = mywfopen(path, "r");
auto len = std::strcspn(linebuf, "\r\n"); if (!fp) return;
linebuf[len] = 0; _LoadLFListFromLineProvider([&](char* buf, size_t sz) {
BufferIO::DecodeUTF8(&linebuf[1], strBuffer); return std::fgets(buf, sz, fp) != nullptr;
LFList newlist; }, insert);
newlist.listName = strBuffer; std::fclose(fp);
newlist.hash = 0x7dfcee6a; }
_lfList.push_back(newlist); #if defined(SERVER_ZIP_SUPPORT) || !defined(YGOPRO_SERVER_MODE)
cur = _lfList.rbegin(); void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader, bool insert) {
continue; std::string linebuf;
char ch{};
_LoadLFListFromLineProvider([&](char* buf, size_t sz) {
while (reader->read(&ch, 1)) {
if (ch == '\0') break;
linebuf.push_back(ch);
if (ch == '\n' || linebuf.size() >= sz - 1) {
std::strncpy(buf, linebuf.c_str(), sz - 1);
buf[sz - 1] = '\0';
linebuf.clear();
return true;
} }
if (cur == _lfList.rend())
continue;
unsigned int code = 0;
int count = -1;
if (std::sscanf(linebuf, "%10s%*[ ]%1d", str1, &count) != 2)
continue;
if (count < 0 || count > 2)
continue;
code = std::strtoul(str1, nullptr, 10);
cur->content[code] = count;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
} }
std::fclose(fp); return false;
} }, insert);
reader->drop();
} }
#endif
void DeckManager::LoadLFList() { void DeckManager::LoadLFList() {
#ifdef SERVER_PRO2_SUPPORT #ifdef SERVER_PRO2_SUPPORT
LoadLFListSingle("config/lflist.conf"); LoadLFListSingle("config/lflist.conf");
#endif #endif
#ifdef SERVER_PRO3_SUPPORT #ifdef SERVER_PRO3_SUPPORT
LoadLFListSingle("Data/lflist.conf"); LoadLFListSingle("Data/lflist.conf");
#ifndef _WIN32
LoadLFListSingle("Expansions/lflist.conf");
#endif #endif
#endif
LoadLFListSingle("expansions/lflist.conf");
LoadLFListSingle("specials/lflist.conf"); LoadLFListSingle("specials/lflist.conf");
LoadLFListSingle("lflist.conf"); LoadLFListSingle("lflist.conf");
LFList nolimit; LFList nolimit;
...@@ -299,6 +295,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) { ...@@ -299,6 +295,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#endif #endif
return reader; return reader;
} }
bool DeckManager::LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist) {
LoadDeckFromStream(current_deck, deckStream, is_packlist);
return true; // the above LoadDeck has return value but we ignore it here for now
}
bool DeckManager::LoadCurrentDeck(const wchar_t* file, bool is_packlist) { bool DeckManager::LoadCurrentDeck(const wchar_t* file, bool is_packlist) {
current_deck.clear(); current_deck.clear();
auto reader = OpenDeckReader(file); auto reader = OpenDeckReader(file);
...@@ -333,21 +333,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na ...@@ -333,21 +333,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na
mainGame->deckBuilder.RefreshPackListScroll(); mainGame->deckBuilder.RefreshPackListScroll();
return res; return res;
} }
void DeckManager::SaveDeck(const Deck& deck, std::stringstream& deckStream) {
deckStream << "#created by ..." << std::endl;
deckStream << "#main" << std::endl;
for(size_t i = 0; i < deck.main.size(); ++i)
deckStream << deck.main[i]->first << std::endl;
deckStream << "#extra" << std::endl;
for(size_t i = 0; i < deck.extra.size(); ++i)
deckStream << deck.extra[i]->first << std::endl;
deckStream << "!side" << std::endl;
for(size_t i = 0; i < deck.side.size(); ++i)
deckStream << deck.side[i]->first << std::endl;
}
bool DeckManager::SaveDeck(const Deck& deck, const wchar_t* file) { bool DeckManager::SaveDeck(const Deck& deck, const wchar_t* file) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck")) if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false; return false;
FILE* fp = OpenDeckFile(file, "w"); FILE* fp = OpenDeckFile(file, "w");
if(!fp) if(!fp)
return false; return false;
std::fprintf(fp, "#created by ...\n#main\n"); std::stringstream deckStream;
for(size_t i = 0; i < deck.main.size(); ++i) SaveDeck(deck, deckStream);
std::fprintf(fp, "%u\n", deck.main[i]->first); std::fwrite(deckStream.str().c_str(), 1, deckStream.str().length(), fp);
std::fprintf(fp, "#extra\n");
for(size_t i = 0; i < deck.extra.size(); ++i)
std::fprintf(fp, "%u\n", deck.extra[i]->first);
std::fprintf(fp, "!side\n");
for(size_t i = 0; i < deck.side.size(); ++i)
std::fprintf(fp, "%u\n", deck.side[i]->first);
std::fclose(fp); std::fclose(fp);
return true; return true;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include "data_manager.h" #include "data_manager.h"
#include "bufferio.h"
#ifndef YGOPRO_MAX_DECK #ifndef YGOPRO_MAX_DECK
#define YGOPRO_MAX_DECK 60 #define YGOPRO_MAX_DECK 60
...@@ -66,7 +67,11 @@ public: ...@@ -66,7 +67,11 @@ public:
static char deckBuffer[0x10000]; static char deckBuffer[0x10000];
#endif #endif
void LoadLFListSingle(const char* path); void LoadLFListSingle(const char* path, bool insert = false);
void LoadLFListSingle(const wchar_t* path, bool insert = false);
#if defined(SERVER_ZIP_SUPPORT) || !defined(YGOPRO_SERVER_MODE)
void LoadLFListSingle(irr::io::IReadFile* reader, bool insert = false);
#endif
void LoadLFList(); void LoadLFList();
const wchar_t* GetLFListName(unsigned int lfhash); const wchar_t* GetLFListName(unsigned int lfhash);
const LFList* GetLFList(unsigned int lfhash); const LFList* GetLFList(unsigned int lfhash);
...@@ -74,11 +79,12 @@ public: ...@@ -74,11 +79,12 @@ public:
#ifndef YGOPRO_SERVER_MODE #ifndef YGOPRO_SERVER_MODE
bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false); bool LoadCurrentDeck(const wchar_t* file, bool is_packlist = false);
bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname); bool LoadCurrentDeck(int category_index, const wchar_t* category_name, const wchar_t* deckname);
bool LoadCurrentDeck(std::istringstream& deckStream, bool is_packlist = false);
wchar_t DeckFormatBuffer[128]; wchar_t DeckFormatBuffer[128];
int TypeCount(std::vector<code_pointer> list, unsigned int ctype); int TypeCount(std::vector<code_pointer> list, unsigned int ctype);
bool LoadDeckFromCode(Deck& deck, const unsigned char *code, int len); bool LoadDeckFromCode(Deck& deck, const unsigned char *code, int len);
int SaveDeckToCode(Deck &deck, unsigned char *code); int SaveDeckToCode(Deck &deck, unsigned char *code);
#endif // YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false); static uint32_t LoadDeck(Deck& deck, uint32_t dbuf[], int mainc, int sidec, bool is_packlist = false);
static bool LoadSide(Deck& deck, uint32_t dbuf[], int mainc, int sidec); static bool LoadSide(Deck& deck, uint32_t dbuf[], int mainc, int sidec);
...@@ -89,12 +95,56 @@ public: ...@@ -89,12 +95,56 @@ public:
static FILE* OpenDeckFile(const wchar_t* file, const char* mode); static FILE* OpenDeckFile(const wchar_t* file, const char* mode);
static irr::io::IReadFile* OpenDeckReader(const wchar_t* file); static irr::io::IReadFile* OpenDeckReader(const wchar_t* file);
static bool SaveDeck(const Deck& deck, const wchar_t* file); static bool SaveDeck(const Deck& deck, const wchar_t* file);
static void SaveDeck(const Deck& deck, std::stringstream& deckStream);
static bool DeleteDeck(const wchar_t* file); static bool DeleteDeck(const wchar_t* file);
static bool CreateCategory(const wchar_t* name); static bool CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname); static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
static bool DeleteCategory(const wchar_t* name); static bool DeleteCategory(const wchar_t* name);
static bool SaveDeckArray(const DeckArray& deck, const wchar_t* name); static bool SaveDeckArray(const DeckArray& deck, const wchar_t* name);
#endif // YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
private:
template<typename LineProvider>
void _LoadLFListFromLineProvider(LineProvider getLine, bool insert = false) {
std::vector<LFList> loadedLists;
auto cur = loadedLists.rend(); // 注意:在临时 list 上操作
char line[256]{};
wchar_t strBuffer[256]{};
char str1[16]{};
while (getLine(line, sizeof(line))) {
if (line[0] == '#')
continue;
if (line[0] == '!') {
auto len = std::strcspn(line, "\r\n");
line[len] = 0;
BufferIO::DecodeUTF8(&line[1], strBuffer);
LFList newlist;
newlist.listName = strBuffer;
newlist.hash = 0x7dfcee6a;
loadedLists.push_back(newlist);
cur = loadedLists.rbegin();
continue;
}
if (cur == loadedLists.rend())
continue;
unsigned int code = 0;
int count = -1;
if (std::sscanf(line, "%10s%*[ ]%1d", str1, &count) != 2)
continue;
if (count < 0 || count > 2)
continue;
code = std::strtoul(str1, nullptr, 10);
cur->content[code] = count;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
}
if (insert) {
_lfList.insert(_lfList.begin(), loadedLists.begin(), loadedLists.end());
} else {
_lfList.insert(_lfList.end(), loadedLists.begin(), loadedLists.end());
}
}
}; };
extern DeckManager deckManager; extern DeckManager deckManager;
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "deck_manager.h" #include "deck_manager.h"
#include "sound_manager.h" #include "sound_manager.h"
#include "duelclient.h" #include "duelclient.h"
#include "../ocgcore/common.h"
namespace ygo { namespace ygo {
...@@ -1393,12 +1392,8 @@ void Game::DrawDeckBd() { ...@@ -1393,12 +1392,8 @@ void Game::DrawDeckBd() {
driver->draw2DRectangle(Resize(805, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000); driver->draw2DRectangle(Resize(805, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000);
driver->draw2DRectangleOutline(Resize(804, 159, 1020, 630)); driver->draw2DRectangleOutline(Resize(804, 159, 1020, 630));
} }
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD int max_result = mainGame->gameConf.use_image_load_background_thread ? 9 : 7;
constexpr int MAX_RESULT = 9; for(int i = 0; i < max_result && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) {
#else
constexpr int MAX_RESULT = 7;
#endif
for(int i = 0; i < MAX_RESULT && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) {
code_pointer ptr = deckBuilder.results[i + scrFilter->getPos()]; code_pointer ptr = deckBuilder.results[i + scrFilter->getPos()];
if(i >= 7) if(i >= 7)
{ {
......
This diff is collapsed.
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
#include <vector> #include <vector>
#include <set> #include <set>
#include <random>
#include "network.h" #include "network.h"
#include "../ocgcore/mtrandom.h"
namespace ygo { namespace ygo {
...@@ -65,7 +65,8 @@ private: ...@@ -65,7 +65,8 @@ private:
static unsigned char last_successful_msg[SIZE_NETWORK_BUFFER]; static unsigned char last_successful_msg[SIZE_NETWORK_BUFFER];
static size_t last_successful_msg_length; static size_t last_successful_msg_length;
static wchar_t event_string[256]; static wchar_t event_string[256];
static mt19937 rnd; static std::mt19937 rnd;
static std::uniform_real_distribution<float> real_dist;
static bool is_refreshing; static bool is_refreshing;
static int match_kill; static int match_kill;
static event* resp_event; static event* resp_event;
...@@ -92,7 +93,7 @@ public: ...@@ -92,7 +93,7 @@ public:
static unsigned int LookupHost(char *host); static unsigned int LookupHost(char *host);
static bool LookupSRV(char *hostname, HostResult* result); static bool LookupSRV(char *hostname, HostResult* result);
static bool CheckHostnameSplitter(char *hostname, HostResult *result); static bool CheckHostnameSplitter(char *hostname, HostResult *result);
static HostResult ParseHost(char *hostname, unsigned short port); static HostResult ParseHost(char *hostname);
static void SendPacketToServer(unsigned char proto) { static void SendPacketToServer(unsigned char proto) {
auto p = duel_client_write; auto p = duel_client_write;
buffer_write<uint16_t>(p, 1); buffer_write<uint16_t>(p, 1);
...@@ -105,8 +106,7 @@ public: ...@@ -105,8 +106,7 @@ public:
template<typename ST> template<typename ST>
static void SendPacketToServer(unsigned char proto, const ST& st) { static void SendPacketToServer(unsigned char proto, const ST& st) {
auto p = duel_client_write; auto p = duel_client_write;
if (sizeof(ST) > MAX_DATA_SIZE) static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
return;
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST))); buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto); buffer_write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST)); std::memcpy(p, &st, sizeof(ST));
...@@ -128,7 +128,7 @@ public: ...@@ -128,7 +128,7 @@ public:
bufferevent_write(client_bev, duel_client_write, len + 3); bufferevent_write(client_bev, duel_client_write, len + 3);
} }
static std::vector<HostPacket> hosts; static std::vector<std::wstring> hosts;
static std::vector<std::wstring> hosts_srvpro; static std::vector<std::wstring> hosts_srvpro;
static bool is_srvpro; static bool is_srvpro;
static void BeginRefreshHost(); static void BeginRefreshHost();
......
#include "event_handler.h" #include "event_handler.h"
#include "client_field.h" #include "client_field.h"
#include "math.h"
#include "network.h" #include "network.h"
#include "game.h" #include "game.h"
#include "duelclient.h" #include "duelclient.h"
...@@ -11,7 +10,6 @@ ...@@ -11,7 +10,6 @@
#include "replay_mode.h" #include "replay_mode.h"
#include "single_mode.h" #include "single_mode.h"
#include "materials.h" #include "materials.h"
#include "../ocgcore/common.h"
namespace ygo { namespace ygo {
...@@ -384,9 +382,9 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -384,9 +382,9 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear(); select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) { for (size_t i = 0; i < activatable_cards.size(); ++i) {
if (activatable_cards[i] == menu_card) { if (activatable_cards[i] == menu_card) {
if(activatable_descs[i].second == EDESC_OPERATION) if(activatable_descs[i].second & EDESC_OPERATION)
continue; continue;
else if(activatable_descs[i].second == EDESC_RESET) { else if(activatable_descs[i].second & EDESC_RESET) {
if(id == BUTTON_CMD_ACTIVATE) continue; if(id == BUTTON_CMD_ACTIVATE) continue;
} else { } else {
if(id == BUTTON_CMD_RESET) continue; if(id == BUTTON_CMD_RESET) continue;
...@@ -675,7 +673,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -675,7 +673,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear(); select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) { for (size_t i = 0; i < activatable_cards.size(); ++i) {
if (activatable_cards[i] == command_card) { if (activatable_cards[i] == command_card) {
if(activatable_descs[i].second == EDESC_OPERATION) { if(activatable_descs[i].second & EDESC_OPERATION) {
if(list_command == COMMAND_ACTIVATE) continue; if(list_command == COMMAND_ACTIVATE) continue;
} else { } else {
if(list_command == COMMAND_OPERATION) continue; if(list_command == COMMAND_OPERATION) continue;
...@@ -1322,7 +1320,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) { ...@@ -1322,7 +1320,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case MSG_SELECT_DISFIELD: { case MSG_SELECT_DISFIELD: {
if (!(hovered_location & LOCATION_ONFIELD)) if (!(hovered_location & LOCATION_ONFIELD))
break; break;
unsigned int flag = 1 << (hovered_sequence + (hovered_controler << 4) + ((hovered_location == LOCATION_MZONE) ? 0 : 8)); unsigned int flag = 0x1U << (hovered_sequence + (hovered_controler << 4) + ((hovered_location == LOCATION_MZONE) ? 0 : 8));
if (flag & selectable_field) { if (flag & selectable_field) {
if (flag & selected_field) { if (flag & selected_field) {
selected_field &= ~flag; selected_field &= ~flag;
......
This diff is collapsed.
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
#include "deck_con.h" #include "deck_con.h"
#include "menu_handler.h" #include "menu_handler.h"
#include "CGUISkinSystem/CGUISkinSystem.h" #include "CGUISkinSystem/CGUISkinSystem.h"
#include <ctime>
#else #else
#include "netserver.h" #include "netserver.h"
#endif //YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
#include <ctime>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <list> #include <list>
...@@ -37,18 +37,40 @@ constexpr int TEXT_LINE_SIZE = 256; ...@@ -37,18 +37,40 @@ constexpr int TEXT_LINE_SIZE = 256;
namespace ygo { namespace ygo {
bool IsExtension(const wchar_t* filename, const wchar_t* extension); template<size_t N>
bool IsExtension(const char* filename, const char* extension); bool IsExtension(const wchar_t* filename, const wchar_t(&extension)[N]) {
auto flen = std::wcslen(filename);
constexpr size_t elen = N - 1;
if (!elen || flen < elen)
return false;
return !mywcsncasecmp(filename + (flen - elen), extension, elen);
}
template<size_t N>
bool IsExtension(const char* filename, const char(&extension)[N]) {
auto flen = std::strlen(filename);
constexpr size_t elen = N - 1;
if (!elen || flen < elen)
return false;
return !mystrncasecmp(filename + (flen - elen), extension, elen);
}
#ifndef YGOPRO_SERVER_MODE #ifndef YGOPRO_SERVER_MODE
struct Config { struct Config {
bool use_d3d{ false }; bool use_d3d{ false };
bool use_image_scale{ true }; bool use_image_scale{ true };
bool use_image_scale_multi_thread{ true };
#ifdef _OPENMP
bool use_image_load_background_thread{ false };
#else
bool use_image_load_background_thread{ true };
#endif
bool freever{ true };
unsigned short antialias{ 0 }; unsigned short antialias{ 0 };
unsigned short serverport{ 7911 }; unsigned short serverport{ 7911 };
unsigned char textfontsize{ 14 }; unsigned char textfontsize{ 14 };
wchar_t lasthost[100]{}; wchar_t lasthost[100]{};
wchar_t lastport[10]{}; // wchar_t lastport[10]{};
wchar_t nickname[20]{}; wchar_t nickname[20]{};
wchar_t gamename[20]{}; wchar_t gamename[20]{};
wchar_t roompass[20]{}; wchar_t roompass[20]{};
...@@ -172,23 +194,32 @@ public: ...@@ -172,23 +194,32 @@ public:
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
void MainServerLoop(); void MainServerLoop();
void MainTestLoop(int code); void MainTestLoop(int code);
void LoadExpansions(); void LoadExpansions(const wchar_t* expansions_path);
void LoadExpansionsAll();
std::vector<std::wstring> GetExpansionsList(const wchar_t * suffix = nullptr);
std::vector<std::string> GetExpansionsListU(const char* suffix = nullptr);
void AddDebugMsg(const char* msgbuf); void AddDebugMsg(const char* msgbuf);
void initUtils(); void initUtils();
void InjectEnvToRegistry(intptr_t pduel);
#else #else
void MainLoop(); void MainLoop();
void RefreshTimeDisplay(); void RefreshTimeDisplay();
void BuildProjectionMatrix(irr::core::matrix4& mProjection, irr::f32 left, irr::f32 right, irr::f32 bottom, irr::f32 top, irr::f32 znear, irr::f32 zfar); void BuildProjectionMatrix(irr::core::matrix4& mProjection, irr::f32 left, irr::f32 right, irr::f32 bottom, irr::f32 top, irr::f32 znear, irr::f32 zfar);
void InitStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::u32 cHeight, irr::gui::CGUITTFont* font, const wchar_t* text); void InitStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::u32 cHeight, irr::gui::CGUITTFont* font, const wchar_t* text);
std::wstring SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::gui::CGUITTFont* font, const wchar_t* text, irr::u32 pos = 0); std::wstring SetStaticText(irr::gui::IGUIStaticText* pControl, irr::u32 cWidth, irr::gui::CGUITTFont* font, const wchar_t* text, irr::u32 pos = 0);
void LoadExpansions(); void LoadExpansions(const wchar_t* expansions_path);
void RefreshCategoryDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck, bool selectlastused = true); void LoadExpansionsAll();
std::vector<std::wstring> GetExpansionsList(const wchar_t * suffix = nullptr);
std::vector<std::string> GetExpansionsListU(const char* suffix = nullptr);
void RefreshCategoryDeck(irr::gui::IGUIComboBox *cbCategory, irr::gui::IGUIComboBox *cbDeck, bool selectlastused = true);
void RefreshDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck); void RefreshDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck);
void RefreshDeck(const wchar_t* deckpath, const std::function<void(const wchar_t*)>& additem); void RefreshDeck(const wchar_t* deckpath, const std::function<void(const wchar_t*)>& additem);
void RefreshReplay(); void RefreshReplay();
void RefreshSingleplay(); void RefreshSingleplay();
void RefreshBot(); void RefreshBot();
void RefreshLocales(); void RefreshLocales();
void RefreshLFList();
void RefreshServerList();
void DrawSelectionLine(irr::video::S3DVertex* vec, bool strip, int width, float* cv); void DrawSelectionLine(irr::video::S3DVertex* vec, bool strip, int width, float* cv);
void DrawSelectionLine(irr::gui::IGUIElement* element, int width, irr::video::SColor color); void DrawSelectionLine(irr::gui::IGUIElement* element, int width, irr::video::SColor color);
void DrawBackGround(); void DrawBackGround();
...@@ -263,6 +294,7 @@ public: ...@@ -263,6 +294,7 @@ public:
void FlashWindow(); void FlashWindow();
void takeScreenshot(); void takeScreenshot();
void SetCursor(irr::gui::ECURSOR_ICON icon); void SetCursor(irr::gui::ECURSOR_ICON icon);
void InjectEnvToRegistry(intptr_t pduel);
template<typename T> template<typename T>
static void DrawShadowText(irr::gui::CGUITTFont* font, const T& text, const irr::core::rect<irr::s32>& position, const irr::core::rect<irr::s32>& padding, static void DrawShadowText(irr::gui::CGUITTFont* font, const T& text, const irr::core::rect<irr::s32>& position, const irr::core::rect<irr::s32>& padding,
irr::video::SColor color = 0xffffffff, irr::video::SColor shadowcolor = 0xff000000, bool hcenter = false, bool vcenter = false, const irr::core::rect<irr::s32>* clip = nullptr); irr::video::SColor color = 0xffffffff, irr::video::SColor shadowcolor = 0xff000000, bool hcenter = false, bool vcenter = false, const irr::core::rect<irr::s32>* clip = nullptr);
...@@ -343,7 +375,7 @@ public: ...@@ -343,7 +375,7 @@ public:
irr::gui::CGUITTFont* numFont; irr::gui::CGUITTFont* numFont;
irr::gui::CGUITTFont* adFont; irr::gui::CGUITTFont* adFont;
irr::gui::CGUITTFont* lpcFont; irr::gui::CGUITTFont* lpcFont;
std::map<irr::gui::CGUIImageButton*, int> imageLoading; std::unordered_map<irr::gui::CGUIImageButton*, int> imageLoading;
//card image //card image
irr::gui::IGUIStaticText* wCardImg; irr::gui::IGUIStaticText* wCardImg;
irr::gui::IGUIImage* imgCard; irr::gui::IGUIImage* imgCard;
...@@ -411,7 +443,6 @@ public: ...@@ -411,7 +443,6 @@ public:
irr::gui::IGUIListBox* lstHostList; irr::gui::IGUIListBox* lstHostList;
irr::gui::IGUIButton* btnLanRefresh; irr::gui::IGUIButton* btnLanRefresh;
irr::gui::IGUIEditBox* ebJoinHost; irr::gui::IGUIEditBox* ebJoinHost;
irr::gui::IGUIEditBox* ebJoinPort;
irr::gui::IGUIEditBox* ebJoinPass; irr::gui::IGUIEditBox* ebJoinPass;
irr::gui::IGUIButton* btnJoinHost; irr::gui::IGUIButton* btnJoinHost;
irr::gui::IGUIButton* btnJoinCancel; irr::gui::IGUIButton* btnJoinCancel;
...@@ -616,6 +647,8 @@ public: ...@@ -616,6 +647,8 @@ public:
irr::gui::IGUIButton* btnDMDeleteDeck; irr::gui::IGUIButton* btnDMDeleteDeck;
irr::gui::IGUIButton* btnMoveDeck; irr::gui::IGUIButton* btnMoveDeck;
irr::gui::IGUIButton* btnCopyDeck; irr::gui::IGUIButton* btnCopyDeck;
irr::gui::IGUIButton* btnImportDeckCode;
irr::gui::IGUIButton* btnExportDeckCode;
irr::gui::IGUIWindow* wDMQuery; irr::gui::IGUIWindow* wDMQuery;
irr::gui::IGUIStaticText* stDMMessage; irr::gui::IGUIStaticText* stDMMessage;
irr::gui::IGUIStaticText* stDMMessage2; irr::gui::IGUIStaticText* stDMMessage2;
...@@ -680,17 +713,25 @@ public: ...@@ -680,17 +713,25 @@ public:
irr::gui::IGUIButton* btnBigCardZoomIn; irr::gui::IGUIButton* btnBigCardZoomIn;
irr::gui::IGUIButton* btnBigCardZoomOut; irr::gui::IGUIButton* btnBigCardZoomOut;
irr::gui::IGUIButton* btnBigCardClose; irr::gui::IGUIButton* btnBigCardClose;
//server list
irr::gui::IGUIButton* btnServerList;
irr::gui::IGUIWindow* wServerList;
irr::gui::IGUIListBox* lstServerList;
irr::gui::IGUIButton* btnServerReturn;
#endif //YGOPRO_SERVER_MODE #endif //YGOPRO_SERVER_MODE
}; };
extern Game* mainGame; extern Game* mainGame;
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
#define MAX_MATCH_COUNT 3
extern unsigned short server_port; extern unsigned short server_port;
extern unsigned short replay_mode; extern unsigned short replay_mode;
extern HostInfo game_info; extern HostInfo game_info;
extern unsigned int pre_seed[5]; extern uint32_t pre_seed[MAX_MATCH_COUNT][SEED_COUNT];
extern unsigned int duel_flags; extern uint8_t pre_seed_specified[MAX_MATCH_COUNT];
extern uint32_t duel_flags;
#endif #endif
} }
...@@ -882,6 +923,8 @@ extern unsigned int duel_flags; ...@@ -882,6 +923,8 @@ extern unsigned int duel_flags;
#define LISTBOX_DECKS 340 #define LISTBOX_DECKS 340
#define BUTTON_DM_OK 341 #define BUTTON_DM_OK 341
#define BUTTON_DM_CANCEL 342 #define BUTTON_DM_CANCEL 342
#define BUTTON_IMPORT_DECK_CODE 343
#define BUTTON_EXPORT_DECK_CODE 344
#define COMBOBOX_LFLIST 349 #define COMBOBOX_LFLIST 349
#define BUTTON_CLEAR_LOG 350 #define BUTTON_CLEAR_LOG 350
...@@ -917,6 +960,10 @@ extern unsigned int duel_flags; ...@@ -917,6 +960,10 @@ extern unsigned int duel_flags;
#define BUTTON_DECK_CODE_SAVE 390 #define BUTTON_DECK_CODE_SAVE 390
#define BUTTON_DECK_CODE_CANCEL 391 #define BUTTON_DECK_CODE_CANCEL 391
#define BUTTON_SERVER_LIST 392
#define LISTBOX_SERVER_LIST 393
#define BUTTON_SERVER_RETURN 394
#define TEXTURE_DUEL 0 #define TEXTURE_DUEL 0
#define TEXTURE_DECK 1 #define TEXTURE_DECK 1
#define TEXTURE_MENU 2 #define TEXTURE_MENU 2
......
...@@ -8,8 +8,17 @@ ...@@ -8,8 +8,17 @@
#ifdef __APPLE__ #ifdef __APPLE__
#import <CoreFoundation/CoreFoundation.h> #import <CoreFoundation/CoreFoundation.h>
#endif #endif
#ifdef YGOPRO_SERVER_MODE
#include "base64.h"
#endif
#ifdef YGOPRO_SERVER_MODE
#include <sstream>
#endif
unsigned int enable_log = 0x3; unsigned int enable_log = 0x3;
bool expansions_specified = false;
std::vector<std::wstring> expansions_list;
#ifndef YGOPRO_SERVER_MODE #ifndef YGOPRO_SERVER_MODE
bool exit_on_return = false; bool exit_on_return = false;
bool auto_watch_mode = false; bool auto_watch_mode = false;
...@@ -72,6 +81,36 @@ int main(int argc, char* argv[]) { ...@@ -72,6 +81,36 @@ int main(int argc, char* argv[]) {
ygo::Game _game; ygo::Game _game;
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
enable_log = 1; enable_log = 1;
bool expansions_specified = false;
wchar_t* expansions_env_val = nullptr;
#ifdef _WIN32
expansions_env_val = _wgetenv(L"YGOPRO_EXPANSIONS");
#else
const char* env_utf8 = std::getenv("YGOPRO_EXPANSIONS");
if(env_utf8) {
expansions_env_val = (wchar_t*)malloc(1024 * sizeof(wchar_t));
BufferIO::DecodeUTF8String(env_utf8, expansions_env_val, 1024);
}
#endif
if (expansions_env_val && expansions_env_val[0] != L'\0') {
expansions_specified = true;
std::wstringstream ss(expansions_env_val);
std::wstring item;
while (std::getline(ss, item, L',')) {
if (!item.empty()) {
expansions_list.push_back(item);
}
}
} else {
expansions_specified = false;
expansions_list.push_back(L"./expansions");
#if defined(SERVER_PRO3_SUPPORT) && !defined(_WIN32) && !defined(__APPLE__)
expansions_list.push_back(L"./Expansions");
#endif
}
ygo::server_port = 7911; ygo::server_port = 7911;
ygo::replay_mode = 0; ygo::replay_mode = 0;
ygo::duel_flags = 0; ygo::duel_flags = 0;
...@@ -85,8 +124,8 @@ int main(int argc, char* argv[]) { ...@@ -85,8 +124,8 @@ int main(int argc, char* argv[]) {
ygo::game_info.no_shuffle_deck = false; ygo::game_info.no_shuffle_deck = false;
ygo::game_info.duel_rule = YGOPRO_DEFAULT_DUEL_RULE; ygo::game_info.duel_rule = YGOPRO_DEFAULT_DUEL_RULE;
ygo::game_info.time_limit = 180; ygo::game_info.time_limit = 180;
for (int i = 0; i < 3; ++i) std::memset(ygo::pre_seed, 0, sizeof(ygo::pre_seed));
ygo::pre_seed[i] = (unsigned int)0; std::memset(ygo::pre_seed_specified, 0, sizeof(ygo::pre_seed_specified));
if (argc == 2) { if (argc == 2) {
int code = atoi(argv[1]); int code = atoi(argv[1]);
ygo::mainGame = &_game; ygo::mainGame = &_game;
...@@ -129,9 +168,28 @@ int main(int argc, char* argv[]) { ...@@ -129,9 +168,28 @@ int main(int argc, char* argv[]) {
ygo::game_info.draw_count = atoi(argv[10]); ygo::game_info.draw_count = atoi(argv[10]);
ygo::game_info.time_limit = atoi(argv[11]); ygo::game_info.time_limit = atoi(argv[11]);
ygo::replay_mode = atoi(argv[12]); ygo::replay_mode = atoi(argv[12]);
for (int i = 13; (i < argc && i <= 17) ; ++i) for (int i = 13; (i < argc && i < (13 + MAX_MATCH_COUNT)) ; ++i)
{ {
ygo::pre_seed[i - 13] = (unsigned int)atol(argv[i]); auto ok = Base64::Decode(
reinterpret_cast<const unsigned char*>(argv[i]),
strlen(argv[i]),
reinterpret_cast<unsigned char*>(ygo::pre_seed[i - 13]),
SEED_COUNT * sizeof(uint32_t)
);
if(ok) {
// check if it isn't all zero
bool all_zero = true;
for (int j = 0; j < SEED_COUNT; ++j) {
if (ygo::pre_seed[i - 13][j] != 0) {
all_zero = false;
break;
}
}
if (!all_zero)
ygo::pre_seed_specified[i - 13] = 1;
}
else
std::fprintf(stderr, "Failed to decode seed %d: %s\n", i - 13, argv[i]);
} }
} }
ygo::mainGame = &_game; ygo::mainGame = &_game;
...@@ -157,7 +215,7 @@ int main(int argc, char* argv[]) { ...@@ -157,7 +215,7 @@ int main(int argc, char* argv[]) {
bool keep_on_return = false; bool keep_on_return = false;
bool deckCategorySpecified = false; bool deckCategorySpecified = false;
bool portSpecified = false; expansions_list.push_back(L"./expansions");
for(int i = 1; i < wargc; ++i) { for(int i = 1; i < wargc; ++i) {
if (wargc == 2 && std::wcslen(wargv[1]) >= 4) { if (wargc == 2 && std::wcslen(wargv[1]) >= 4) {
wchar_t* pstrext = wargv[1] + std::wcslen(wargv[1]) - 4; wchar_t* pstrext = wargv[1] + std::wcslen(wargv[1]) - 4;
...@@ -196,21 +254,17 @@ int main(int argc, char* argv[]) { ...@@ -196,21 +254,17 @@ int main(int argc, char* argv[]) {
++i; ++i;
if(i < wargc) { if(i < wargc) {
ygo::mainGame->ebJoinHost->setText(wargv[i]); ygo::mainGame->ebJoinHost->setText(wargv[i]);
if(!portSpecified)
ygo::mainGame->ebJoinPort->setText(L"");
} }
continue; continue;
} else if(!std::wcscmp(wargv[i], L"-p")) { // host Port } else if(!std::wcscmp(wargv[i], L"-p")) { // host Port
++i; ++i;
if(i < wargc) { if(i < wargc) {
portSpecified = true;
auto port = _wtoi(wargv[i]); auto port = _wtoi(wargv[i]);
if(port) { auto hostText = ygo::mainGame->ebJoinHost->getText();
wchar_t portStr[6]; if(port && hostText) {
myswprintf(portStr, L"%d", port); wchar_t newHostStr[100];
ygo::mainGame->ebJoinPort->setText(portStr); myswprintf(newHostStr, L"%ls:%d", hostText, port);
} else { ygo::mainGame->ebJoinHost->setText(newHostStr);
ygo::mainGame->ebJoinPort->setText(L"");
} }
} }
continue; continue;
...@@ -286,6 +340,16 @@ int main(int argc, char* argv[]) { ...@@ -286,6 +340,16 @@ int main(int argc, char* argv[]) {
if(open_file) if(open_file)
ClickButton(ygo::mainGame->btnLoadSinglePlay); ClickButton(ygo::mainGame->btnLoadSinglePlay);
break; break;
} else if(!std::wcscmp(wargv[i], L"--expansions")) { // specify expansions
++i;
if(i < wargc) {
if(!expansions_specified) {
expansions_list.clear();
expansions_specified = true;
}
expansions_list.push_back(wargv[i]);
}
continue;
} }
} }
ygo::mainGame->MainLoop(); ygo::mainGame->MainLoop();
......
This diff is collapsed.
#ifndef IMAGEMANAGER_H #ifndef IMAGEMANAGER_H
#define IMAGEMANAGER_H #define IMAGEMANAGER_H
#ifndef _OPENMP
#define YGOPRO_USE_THUMB_LOAD_THREAD
#endif
#include "config.h" #include "config.h"
#include "data_manager.h" #include "data_manager.h"
#include <unordered_map> #include <unordered_map>
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
#include <queue> #include <queue>
#include <mutex> #include <mutex>
#endif
namespace ygo { namespace ygo {
...@@ -34,19 +28,15 @@ public: ...@@ -34,19 +28,15 @@ public:
irr::video::ITexture* GetBigPicture(int code, float zoom); irr::video::ITexture* GetBigPicture(int code, float zoom);
irr::video::ITexture* GetTextureThumb(int code); irr::video::ITexture* GetTextureThumb(int code);
irr::video::ITexture* GetTextureField(int code); irr::video::ITexture* GetTextureField(int code);
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
static int LoadThumbThread(); static int LoadThumbThread();
#endif
std::unordered_map<int, irr::video::ITexture*> tMap[2]; std::unordered_map<int, irr::video::ITexture*> tMap[2];
std::unordered_map<int, irr::video::ITexture*> tThumb; std::unordered_map<int, irr::video::ITexture*> tThumb;
std::unordered_map<int, irr::video::ITexture*> tFields; std::unordered_map<int, irr::video::ITexture*> tFields;
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
std::unordered_map<int, irr::video::IImage*> tThumbLoading; std::unordered_map<int, irr::video::IImage*> tThumbLoading;
std::queue<int> tThumbLoadingCodes; std::queue<int> tThumbLoadingCodes;
std::mutex tThumbLoadingMutex; std::mutex tThumbLoadingMutex;
bool tThumbLoadingThreadRunning; bool tThumbLoadingThreadRunning;
#endif
irr::IrrlichtDevice* device; irr::IrrlichtDevice* device;
irr::video::IVideoDriver* driver; irr::video::IVideoDriver* driver;
irr::video::ITexture* tCover[4]; irr::video::ITexture* tCover[4];
...@@ -54,9 +44,7 @@ public: ...@@ -54,9 +44,7 @@ public:
irr::video::ITexture* tUnknownFit; irr::video::ITexture* tUnknownFit;
irr::video::ITexture* tUnknownThumb; irr::video::ITexture* tUnknownThumb;
irr::video::ITexture* tBigPicture; irr::video::ITexture* tBigPicture;
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
irr::video::ITexture* tLoading; irr::video::ITexture* tLoading;
#endif
irr::video::ITexture* tAct; irr::video::ITexture* tAct;
irr::video::ITexture* tAttack; irr::video::ITexture* tAttack;
irr::video::ITexture* tNegated; irr::video::ITexture* tNegated;
......
...@@ -64,15 +64,11 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -64,15 +64,11 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_JOIN_HOST: { case BUTTON_JOIN_HOST: {
bot_mode = false; bot_mode = false;
mainGame->TrimText(mainGame->ebJoinHost); mainGame->TrimText(mainGame->ebJoinHost);
mainGame->TrimText(mainGame->ebJoinPort);
char hostname_tag[100]; char hostname_tag[100];
wchar_t pstr[100]; wchar_t pstr[100];
wchar_t portstr[10];
BufferIO::CopyWideString(mainGame->ebJoinHost->getText(), pstr); BufferIO::CopyWideString(mainGame->ebJoinHost->getText(), pstr);
BufferIO::CopyWideString(mainGame->ebJoinPort->getText(), portstr);
BufferIO::EncodeUTF8(pstr, hostname_tag); BufferIO::EncodeUTF8(pstr, hostname_tag);
auto port = std::wcstol(portstr, nullptr, 10); HostResult remote = DuelClient::ParseHost(hostname_tag);
HostResult remote = DuelClient::ParseHost(hostname_tag, port);
if(!remote.isValid()) { if(!remote.isValid()) {
mainGame->gMutex.lock(); mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO); soundManager.PlaySoundEffect(SOUND_INFO);
...@@ -85,7 +81,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -85,7 +81,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break; break;
} }
BufferIO::CopyWideString(pstr, mainGame->gameConf.lasthost); BufferIO::CopyWideString(pstr, mainGame->gameConf.lasthost);
BufferIO::CopyWideString(portstr, mainGame->gameConf.lastport);
BufferIO::CopyWideString(mainGame->ebJoinPass->getText(), mainGame->gameConf.roompass); BufferIO::CopyWideString(mainGame->ebJoinPass->getText(), mainGame->gameConf.roompass);
if(DuelClient::StartClient(remote.host, remote.port, false)) { if(DuelClient::StartClient(remote.host, remote.port, false)) {
mainGame->btnCreateHost->setEnabled(false); mainGame->btnCreateHost->setEnabled(false);
...@@ -96,6 +91,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -96,6 +91,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
} }
case BUTTON_JOIN_CANCEL: { case BUTTON_JOIN_CANCEL: {
mainGame->HideElement(mainGame->wLanWindow); mainGame->HideElement(mainGame->wLanWindow);
mainGame->HideElement(mainGame->wServerList);
mainGame->ShowElement(mainGame->wMainMenu); mainGame->ShowElement(mainGame->wMainMenu);
if(exit_on_return) if(exit_on_return)
mainGame->device->closeDevice(); mainGame->device->closeDevice();
...@@ -109,6 +105,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -109,6 +105,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->btnHostConfirm->setEnabled(true); mainGame->btnHostConfirm->setEnabled(true);
mainGame->btnHostCancel->setEnabled(true); mainGame->btnHostCancel->setEnabled(true);
mainGame->HideElement(mainGame->wLanWindow); mainGame->HideElement(mainGame->wLanWindow);
mainGame->HideElement(mainGame->wServerList);
mainGame->ShowElement(mainGame->wCreateHost); mainGame->ShowElement(mainGame->wCreateHost);
break; break;
} }
...@@ -220,8 +217,12 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -220,8 +217,12 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_LOAD_REPLAY: { case BUTTON_LOAD_REPLAY: {
int start_turn = 1; int start_turn = 1;
if(open_file) { if(open_file) {
ReplayMode::cur_replay.OpenReplay(open_file_name);
open_file = false; open_file = false;
if (!ReplayMode::cur_replay.OpenReplay(open_file_name)) {
if (exit_on_return)
mainGame->device->closeDevice();
break;
}
} else { } else {
auto selected = mainGame->lstReplayList->getSelected(); auto selected = mainGame->lstReplayList->getSelected();
if(selected == -1) if(selected == -1)
...@@ -295,7 +296,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -295,7 +296,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename); myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path)) if (!replay.OpenReplay(replay_path))
break; break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE) if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break; break;
for (size_t i = 0; i < replay.decks.size(); ++i) { for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]); BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
...@@ -489,6 +490,15 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -489,6 +490,15 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
prev_sel = -1; prev_sel = -1;
break; break;
} }
case BUTTON_SERVER_LIST: {
mainGame->ShowElement(mainGame->wServerList);
mainGame->PopupElement(mainGame->wServerList);
break;
}
case BUTTON_SERVER_RETURN: {
mainGame->HideElement(mainGame->wServerList);
break;
}
} }
break; break;
} }
...@@ -502,21 +512,18 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -502,21 +512,18 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->ebJoinPass->setText(DuelClient::hosts_srvpro[sel].c_str()); mainGame->ebJoinPass->setText(DuelClient::hosts_srvpro[sel].c_str());
break; break;
} }
int addr = DuelClient::hosts[sel].ipaddr; mainGame->ebJoinHost->setText(DuelClient::hosts[sel].c_str());
int port = DuelClient::hosts[sel].port;
wchar_t buf[20];
myswprintf(buf, L"%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff);
mainGame->ebJoinHost->setText(buf);
myswprintf(buf, L"%d", port);
mainGame->ebJoinPort->setText(buf);
break; break;
} }
case LISTBOX_REPLAY_LIST: { case LISTBOX_REPLAY_LIST: {
int sel = mainGame->lstReplayList->getSelected(); int sel = mainGame->lstReplayList->getSelected();
if(sel == -1) if(sel < 0)
break;
auto filename = mainGame->lstReplayList->getListItem(sel);
if (!filename)
break; break;
wchar_t replay_path[256]{}; wchar_t replay_path[256]{};
myswprintf(replay_path, L"./replay/%ls", mainGame->lstReplayList->getListItem(sel)); myswprintf(replay_path, L"./replay/%ls", filename);
if (!temp_replay.OpenReplay(replay_path)) { if (!temp_replay.OpenReplay(replay_path)) {
mainGame->stReplayInfo->setText(L"Error"); mainGame->stReplayInfo->setText(L"Error");
break; break;
...@@ -524,20 +531,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -524,20 +531,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{}; wchar_t infobuf[256]{};
std::wstring repinfo; std::wstring repinfo;
time_t curtime; time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM) const auto& rh = temp_replay.pheader.base;
curtime = temp_replay.pheader.start_time; if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
else curtime = rh.start_time;
curtime = temp_replay.pheader.seed; else{
curtime = rh.seed;
wchar_t version_info[256]{};
myswprintf(version_info, L"version 0x%X\n", rh.version);
repinfo.append(version_info);
}
std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime)); std::wcsftime(infobuf, sizeof infobuf / sizeof infobuf[0], L"%Y/%m/%d %H:%M:%S\n", std::localtime(&curtime));
repinfo.append(infobuf); repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) { if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{}; wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path); BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path); repinfo.append(path);
repinfo.append(L"\n"); repinfo.append(L"\n");
} }
const auto& player_names = temp_replay.players; const auto& player_names = temp_replay.players;
if(temp_replay.pheader.flag & REPLAY_TAG) if(rh.flag & REPLAY_TAG)
myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str()); myswprintf(infobuf, L"%ls\n%ls\n===VS===\n%ls\n%ls\n", player_names[0].c_str(), player_names[1].c_str(), player_names[2].c_str(), player_names[3].c_str());
else else
myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str()); myswprintf(infobuf, L"%ls\n===VS===\n%ls\n", player_names[0].c_str(), player_names[1].c_str());
...@@ -598,6 +610,13 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -598,6 +610,13 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->cbBotDeck->setVisible(mainGame->botInfo[sel].select_deckfile); mainGame->cbBotDeck->setVisible(mainGame->botInfo[sel].select_deckfile);
break; break;
} }
case LISTBOX_SERVER_LIST: {
int sel = mainGame->lstServerList->getSelected();
auto target = sel == -1 ? L"" : dataManager._serverStrings[sel].second.c_str();
BufferIO::CopyWideString(target, mainGame->gameConf.lasthost);
mainGame->ebJoinHost->setText(target);
break;
}
} }
break; break;
} }
......
...@@ -297,7 +297,11 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -297,7 +297,11 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
case CTOS_CHAT: { case CTOS_CHAT: {
if(!dp->game) if(!dp->game)
return; return;
if (len < 1 + (int)sizeof(unsigned char)) if (len < 1 + sizeof(uint16_t) * 1)
return;
if (len > 1 + sizeof(uint16_t) * LEN_CHAT_MSG)
return;
if ((len - 1) % sizeof(uint16_t))
return; return;
duel_mode->Chat(dp, pdata, len - 1); duel_mode->Chat(dp, pdata, len - 1);
break; break;
...@@ -344,6 +348,15 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -344,6 +348,15 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
BufferIO::CopyCharArray(pkt->name, dp->name); BufferIO::CopyCharArray(pkt->name, dp->name);
break; break;
} }
case CTOS_EXTERNAL_ADDRESS: {
// for other server & reverse proxy use only
/*
wchar_t hostname[LEN_HOSTNAME];
uint32_t real_ip = ntohl(BufferIO::ReadInt32(pdata));
BufferIO::CopyCharArray((uint16_t*)pdata, hostname);
*/
break;
}
case CTOS_CREATE_GAME: { case CTOS_CREATE_GAME: {
if(dp->game || duel_mode) if(dp->game || duel_mode)
return; return;
...@@ -424,6 +437,14 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -424,6 +437,14 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
duel_mode->ToObserver(dp); duel_mode->ToObserver(dp);
break; break;
} }
#ifdef YGOPRO_SERVER_MODE
case CTOS_HS_NOTREADY: {
if (!duel_mode || duel_mode->pduel)
return;
duel_mode->PlayerReady(dp, false);
break;
}
#else
case CTOS_HS_READY: case CTOS_HS_READY:
case CTOS_HS_NOTREADY: { case CTOS_HS_NOTREADY: {
if (!duel_mode || duel_mode->pduel) if (!duel_mode || duel_mode->pduel)
...@@ -431,6 +452,7 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -431,6 +452,7 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
duel_mode->PlayerReady(dp, (CTOS_HS_NOTREADY - pktType) != 0); duel_mode->PlayerReady(dp, (CTOS_HS_NOTREADY - pktType) != 0);
break; break;
} }
#endif
case CTOS_HS_KICK: { case CTOS_HS_KICK: {
if (!duel_mode || duel_mode->pduel) if (!duel_mode || duel_mode->pduel)
return; return;
...@@ -459,8 +481,6 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) { ...@@ -459,8 +481,6 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
} }
} }
size_t NetServer::CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type) { size_t NetServer::CreateChatPacket(unsigned char* src, int src_size, unsigned char* dst, uint16_t dst_player_type) {
if (!check_msg_size(src_size))
return 0;
uint16_t src_msg[LEN_CHAT_MSG]; uint16_t src_msg[LEN_CHAT_MSG];
std::memcpy(src_msg, src, src_size); std::memcpy(src_msg, src, src_size);
const int src_len = src_size / sizeof(uint16_t); const int src_len = src_size / sizeof(uint16_t);
......
...@@ -58,8 +58,7 @@ public: ...@@ -58,8 +58,7 @@ public:
template<typename ST> template<typename ST>
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, const ST& st) { static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, const ST& st) {
auto p = net_server_write; auto p = net_server_write;
if (sizeof(ST) > MAX_DATA_SIZE) static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
return;
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST))); buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto); buffer_write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST)); std::memcpy(p, &st, sizeof(ST));
......
...@@ -103,6 +103,14 @@ struct CTOS_Kick { ...@@ -103,6 +103,14 @@ struct CTOS_Kick {
check_trivially_copyable(CTOS_Kick); check_trivially_copyable(CTOS_Kick);
static_assert(sizeof(CTOS_Kick) == 1, "size mismatch: CTOS_Kick"); static_assert(sizeof(CTOS_Kick) == 1, "size mismatch: CTOS_Kick");
/*
* CTOS_ExternalAddress
* uint32_t real_ip; (IPv4 address, BE, alway 0 in normal client)
* uint16_t hostname[256]; (UTF-16 string)
*/
constexpr int LEN_HOSTNAME = 256;
// STOC // STOC
struct STOC_ErrorMsg { struct STOC_ErrorMsg {
uint8_t msg{}; uint8_t msg{};
...@@ -196,17 +204,6 @@ struct DuelPlayer { ...@@ -196,17 +204,6 @@ struct DuelPlayer {
bufferevent* bev{}; bufferevent* bev{};
}; };
inline bool check_msg_size(int size) {
// empty string is not allowed
if (size < 2 * sizeof(uint16_t))
return false;
if (size > LEN_CHAT_MSG * sizeof(uint16_t))
return false;
if (size % sizeof(uint16_t) != 0)
return false;
return true;
}
inline unsigned int GetPosition(unsigned char* qbuf, size_t offset) { inline unsigned int GetPosition(unsigned char* qbuf, size_t offset) {
unsigned int info = 0; unsigned int info = 0;
std::memcpy(&info, qbuf + offset, sizeof info); std::memcpy(&info, qbuf + offset, sizeof info);
...@@ -249,6 +246,7 @@ public: ...@@ -249,6 +246,7 @@ public:
intptr_t pduel{}; intptr_t pduel{};
wchar_t name[20]{}; wchar_t name[20]{};
wchar_t pass[20]{}; wchar_t pass[20]{};
std::vector<byte> registry_dump;
}; };
} }
...@@ -275,6 +273,7 @@ public: ...@@ -275,6 +273,7 @@ public:
#define CTOS_SURRENDER 0x14 // no data #define CTOS_SURRENDER 0x14 // no data
#define CTOS_TIME_CONFIRM 0x15 // no data #define CTOS_TIME_CONFIRM 0x15 // no data
#define CTOS_CHAT 0x16 // uint16_t array #define CTOS_CHAT 0x16 // uint16_t array
#define CTOS_EXTERNAL_ADDRESS 0x17 // CTOS_ExternalAddress
#define CTOS_HS_TODUELIST 0x20 // no data #define CTOS_HS_TODUELIST 0x20 // no data
#define CTOS_HS_TOOBSERVER 0x21 // no data #define CTOS_HS_TOOBSERVER 0x21 // no data
#define CTOS_HS_READY 0x22 // no data #define CTOS_HS_READY 0x22 // no data
...@@ -298,7 +297,7 @@ public: ...@@ -298,7 +297,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved #define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // no data #define STOC_DUEL_START 0x15 // no data
#define STOC_DUEL_END 0x16 // no data #define STOC_DUEL_END 0x16 // no data
#define STOC_REPLAY 0x17 // ReplayHeader + byte array #define STOC_REPLAY 0x17 // ExtendedReplayHeader + byte array
#define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit #define STOC_TIME_LIMIT 0x18 // STOC_TimeLimit
#define STOC_CHAT 0x19 // uint16_t + uint16_t array #define STOC_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter #define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
...@@ -45,7 +45,6 @@ end ...@@ -45,7 +45,6 @@ end
else else
project "ygopro" project "ygopro"
kind "WindowedApp" kind "WindowedApp"
cppdialect "C++14"
rtti "Off" rtti "Off"
openmp "On" openmp "On"
...@@ -54,11 +53,16 @@ project "ygopro" ...@@ -54,11 +53,16 @@ project "ygopro"
links { "ocgcore", "clzma", "cspmemvfs", LUA_LIB_NAME, "sqlite3", "irrlicht", "freetype", "event" } links { "ocgcore", "clzma", "cspmemvfs", LUA_LIB_NAME, "sqlite3", "irrlicht", "freetype", "event" }
end end
if not BUILD_LUA then
libdirs { LUA_LIB_DIR }
end
if BUILD_EVENT then if BUILD_EVENT then
includedirs { "../event/include" } includedirs { "../event/include" }
else else
includedirs { EVENT_INCLUDE_DIR } includedirs { EVENT_INCLUDE_DIR }
libdirs { EVENT_LIB_DIR } libdirs { EVENT_LIB_DIR }
links { "event_pthreads" }
end end
if BUILD_IRRLICHT then if BUILD_IRRLICHT then
...@@ -82,7 +86,7 @@ end ...@@ -82,7 +86,7 @@ end
libdirs { SQLITE_LIB_DIR } libdirs { SQLITE_LIB_DIR }
end end
if USE_AUDIO then if USE_AUDIO and not SERVER_MODE then
defines { "YGOPRO_USE_AUDIO" } defines { "YGOPRO_USE_AUDIO" }
if AUDIO_LIB == "miniaudio" then if AUDIO_LIB == "miniaudio" then
defines { "YGOPRO_USE_MINIAUDIO" } defines { "YGOPRO_USE_MINIAUDIO" }
...@@ -110,43 +114,53 @@ end ...@@ -110,43 +114,53 @@ end
end end
filter "system:windows" filter "system:windows"
entrypoint "mainCRTStartup"
defines { "_IRR_WCHAR_FILESYSTEM" } defines { "_IRR_WCHAR_FILESYSTEM" }
files "ygopro.rc" files "ygopro.rc"
if SERVER_PRO2_SUPPORT then if SERVER_PRO2_SUPPORT then
targetname ("AI.Server") targetname ("AI.Server")
end end
if SERVER_MODE then if SERVER_MODE then
links { "ws2_32" } links { "ws2_32", "iphlpapi" }
else else
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32", "Dnsapi" } links { "ws2_32", "Dnsapi", "iphlpapi" }
end end
if USE_AUDIO and AUDIO_LIB == "irrklang" then if USE_AUDIO and AUDIO_LIB == "irrklang" then
links { "irrKlang" } links { "irrKlang" }
if IRRKLANG_PRO then if IRRKLANG_PRO then
defines { "IRRKLANG_STATIC" } defines { "IRRKLANG_STATIC" }
filter { "not configurations:Debug" } filter { "system:windows", "not configurations:Debug" }
libdirs { IRRKLANG_PRO_RELEASE_LIB_DIR } libdirs { IRRKLANG_PRO_RELEASE_LIB_DIR }
filter { "configurations:Debug" } filter { "system:windows", "configurations:Debug" }
libdirs { IRRKLANG_PRO_DEBUG_LIB_DIR } libdirs { IRRKLANG_PRO_DEBUG_LIB_DIR }
filter {} filter {}
end end
end end
if not SERVER_MODE then
filter "not system:windows" filter "not system:windows"
links { "event_pthreads", "dl", "pthread", "resolv" } links { "resolv" }
end
filter "not action:vs*"
cppdialect "C++14"
filter "system:macosx" filter "system:macosx"
if not SERVER_MODE then if not SERVER_MODE then
openmp "Off" openmp "Off"
links { "z" } links { "OpenGL.framework", "Cocoa.framework", "IOKit.framework" }
defines { "GL_SILENCE_DEPRECATION" } defines { "GL_SILENCE_DEPRECATION" }
end end
if MAC_ARM then if MAC_ARM then
buildoptions { "--target=arm64-apple-macos12" }
linkoptions { "-arch arm64" } linkoptions { "-arch arm64" }
end end
if MAC_INTEL then
linkoptions { "-arch x86_64" }
end
if USE_AUDIO and AUDIO_LIB == "irrklang" then if USE_AUDIO and AUDIO_LIB == "irrklang" then
links { "irrklang" } links { "irrklang" }
end end
filter "system:linux" filter "system:linux"
links { "dl", "pthread" }
linkoptions { "-static-libstdc++", "-static-libgcc" } linkoptions { "-static-libstdc++", "-static-libgcc" }
if not SERVER_MODE then if not SERVER_MODE then
links { "GL", "X11", "Xxf86vm" } links { "GL", "X11", "Xxf86vm" }
......
...@@ -48,7 +48,7 @@ void Replay::BeginRecord() { ...@@ -48,7 +48,7 @@ void Replay::BeginRecord() {
char tmppath[40]; char tmppath[40];
strftime(tmppath, 40, "./replay/%Y-%m-%d %H-%M-%S %%u.yrp", localedtime); strftime(tmppath, 40, "./replay/%Y-%m-%d %H-%M-%S %%u.yrp", localedtime);
char path[40]; char path[40];
std::sprintf(path, tmppath, server_port); sprintf(path, tmppath, server_port);
fp = myfopen(path, "wb"); fp = myfopen(path, "wb");
#else #else
fp = myfopen("./replay/_LastReplay.yrp", "wb"); fp = myfopen("./replay/_LastReplay.yrp", "wb");
...@@ -62,7 +62,7 @@ void Replay::BeginRecord() { ...@@ -62,7 +62,7 @@ void Replay::BeginRecord() {
Reset(); Reset();
is_recording = true; is_recording = true;
} }
void Replay::WriteHeader(ReplayHeader& header) { void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header; pheader = header;
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return; if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
...@@ -122,11 +122,11 @@ void Replay::EndRecord() { ...@@ -122,11 +122,11 @@ void Replay::EndRecord() {
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
} }
#endif #endif
pheader.datasize = replay_size; pheader.base.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED; pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5; size_t propsize = 5;
comp_size = MAX_COMP_SIZE; comp_size = MAX_COMP_SIZE;
int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.props, &propsize, 5, 1 << 24, 3, 0, 2, 32, 1); int ret = LzmaCompress(comp_data, &comp_size, replay_data, replay_size, pheader.base.props, &propsize, 5, 0x1U << 24, 3, 0, 2, 32, 1);
if (ret != SZ_OK) { if (ret != SZ_OK) {
std::memcpy(comp_data, &ret, sizeof ret); std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret; comp_size = sizeof ret;
...@@ -145,6 +145,7 @@ void Replay::SaveReplay(const wchar_t* name) { ...@@ -145,6 +145,7 @@ void Replay::SaveReplay(const wchar_t* name) {
std::fwrite(comp_data, comp_size, 1, rfp); std::fwrite(comp_data, comp_size, 1, rfp);
std::fclose(rfp); std::fclose(rfp);
} }
#ifndef YGOPRO_SERVER_MODE
bool Replay::OpenReplay(const wchar_t* name) { bool Replay::OpenReplay(const wchar_t* name) {
FILE* rfp = mywfopen(name, "rb"); FILE* rfp = mywfopen(name, "rb");
if(!rfp) { if(!rfp) {
...@@ -156,19 +157,32 @@ bool Replay::OpenReplay(const wchar_t* name) { ...@@ -156,19 +157,32 @@ bool Replay::OpenReplay(const wchar_t* name) {
return false; return false;
Reset(); Reset();
if(std::fread(&pheader, sizeof pheader, 1, rfp) < 1) { bool correct_header = true;
if (std::fread(&pheader, sizeof pheader.base, 1, rfp) < 1)
correct_header = false;
else if (pheader.base.id != REPLAY_ID_YRP1 && pheader.base.id != REPLAY_ID_YRP2)
correct_header = false;
else if (pheader.base.version < 0x12d0u)
correct_header = false;
else if (pheader.base.version >= 0x1353u && !(pheader.base.flag & REPLAY_UNIFORM))
correct_header = false;
if (!correct_header) {
std::fclose(rfp); std::fclose(rfp);
return false; return false;
} }
if(pheader.flag & REPLAY_COMPRESSED) { if (pheader.base.id == REPLAY_ID_YRP2 && std::fread(reinterpret_cast<unsigned char*>(&pheader) + sizeof pheader.base, sizeof pheader - sizeof pheader.base, 1, rfp) < 1) {
std::fclose(rfp);
return false;
}
if(pheader.base.flag & REPLAY_COMPRESSED) {
comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp); comp_size = std::fread(comp_data, 1, MAX_COMP_SIZE, rfp);
std::fclose(rfp); std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE) if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false; return false;
replay_size = pheader.datasize; replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK) if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false; return false;
if (replay_size != pheader.datasize) { if (replay_size != pheader.base.datasize) {
replay_size = 0; replay_size = 0;
return false; return false;
} }
...@@ -187,17 +201,6 @@ bool Replay::OpenReplay(const wchar_t* name) { ...@@ -187,17 +201,6 @@ bool Replay::OpenReplay(const wchar_t* name) {
data_position = 0; data_position = 0;
return true; return true;
} }
bool Replay::CheckReplay(const wchar_t* name) {
wchar_t fname[256];
myswprintf(fname, L"./replay/%ls", name);
FILE* rfp = mywfopen(fname, "rb");
if(!rfp)
return false;
ReplayHeader rheader;
size_t count = std::fread(&rheader, sizeof rheader, 1, rfp);
std::fclose(rfp);
return count == 1 && rheader.id == 0x31707279 && rheader.version >= 0x12d0u && (rheader.version < 0x1353u || (rheader.flag & REPLAY_UNIFORM));
}
bool Replay::DeleteReplay(const wchar_t* name) { bool Replay::DeleteReplay(const wchar_t* name) {
wchar_t fname[256]; wchar_t fname[256];
myswprintf(fname, L"./replay/%ls", name); myswprintf(fname, L"./replay/%ls", name);
...@@ -236,7 +239,7 @@ bool Replay::ReadName(wchar_t* data) { ...@@ -236,7 +239,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20); BufferIO::CopyWStr(buffer, data, 20);
return true; return true;
} }
void Replay::ReadHeader(ReplayHeader& header) { void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader; header = pheader;
} }
bool Replay::ReadData(void* data, size_t length) { bool Replay::ReadData(void* data, size_t length) {
...@@ -258,6 +261,7 @@ void Replay::Rewind() { ...@@ -258,6 +261,7 @@ void Replay::Rewind() {
data_position = 0; data_position = 0;
can_read = true; can_read = true;
} }
#endif // YGOPRO_SERVER_MODE
void Replay::Reset() { void Replay::Reset() {
is_recording = false; is_recording = false;
is_replaying = false; is_replaying = false;
...@@ -271,6 +275,7 @@ void Replay::Reset() { ...@@ -271,6 +275,7 @@ void Replay::Reset() {
decks.clear(); decks.clear();
script_name.clear(); script_name.clear();
} }
#ifndef YGOPRO_SERVER_MODE
void Replay::SkipInfo(){ void Replay::SkipInfo(){
if (data_position == 0) if (data_position == 0)
data_position += info_offset; data_position += info_offset;
...@@ -279,7 +284,7 @@ bool Replay::IsReplaying() const { ...@@ -279,7 +284,7 @@ bool Replay::IsReplaying() const {
return is_replaying; return is_replaying;
} }
bool Replay::ReadInfo() { bool Replay::ReadInfo() {
int player_count = (pheader.flag & REPLAY_TAG) ? 4 : 2; int player_count = (pheader.base.flag & REPLAY_TAG) ? 4 : 2;
for (int i = 0; i < player_count; ++i) { for (int i = 0; i < player_count; ++i) {
wchar_t name[20]{}; wchar_t name[20]{};
if (!ReadName(name)) if (!ReadName(name))
...@@ -288,11 +293,11 @@ bool Replay::ReadInfo() { ...@@ -288,11 +293,11 @@ bool Replay::ReadInfo() {
} }
if (!ReadData(&params, sizeof params)) if (!ReadData(&params, sizeof params))
return false; return false;
bool is_tag1 = pheader.flag & REPLAY_TAG; bool is_tag1 = pheader.base.flag & REPLAY_TAG;
bool is_tag2 = params.duel_flag & DUEL_TAG_MODE; bool is_tag2 = params.duel_flag & DUEL_TAG_MODE;
if (is_tag1 != is_tag2) if (is_tag1 != is_tag2)
return false; return false;
if (pheader.flag & REPLAY_SINGLE_MODE) { if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>(); uint16_t slen = Read<uint16_t>();
char filename[256]{}; char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1) if (slen == 0 || slen > sizeof(filename) - 1)
...@@ -328,5 +333,6 @@ bool Replay::ReadInfo() { ...@@ -328,5 +333,6 @@ bool Replay::ReadInfo() {
} }
return true; return true;
} }
#endif // YGOPRO_SERVER_MODE
} }
...@@ -13,6 +13,9 @@ namespace ygo { ...@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8 #define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10 #define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size // max size
constexpr int MAX_REPLAY_SIZE = 0x80000; constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1; constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
...@@ -36,6 +39,15 @@ struct ReplayHeader { ...@@ -36,6 +39,15 @@ struct ReplayHeader {
uint8_t props[8]{}; uint8_t props[8]{};
}; };
struct ExtendedReplayHeader {
ReplayHeader base;
uint32_t seed_sequence[SEED_COUNT]{};
uint32_t header_version{ 1 };
uint32_t value1{};
uint32_t value2{};
uint32_t value3{};
};
struct DuelParameters { struct DuelParameters {
int32_t start_lp{}; int32_t start_lp{};
int32_t start_hand{}; int32_t start_hand{};
...@@ -50,7 +62,7 @@ public: ...@@ -50,7 +62,7 @@ public:
// record // record
void BeginRecord(); void BeginRecord();
void WriteHeader(ReplayHeader& header); void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true); void WriteData(const void* data, size_t length, bool flush = true);
template<typename T> template<typename T>
void Write(T data, bool flush = true) { void Write(T data, bool flush = true) {
...@@ -62,7 +74,6 @@ public: ...@@ -62,7 +74,6 @@ public:
void SaveReplay(const wchar_t* name); void SaveReplay(const wchar_t* name);
// play // play
static bool CheckReplay(const wchar_t* name);
static bool DeleteReplay(const wchar_t* name); static bool DeleteReplay(const wchar_t* name);
static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname); static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname);
static size_t GetDeckPlayer(size_t deck_index) { static size_t GetDeckPlayer(size_t deck_index) {
...@@ -75,10 +86,13 @@ public: ...@@ -75,10 +86,13 @@ public:
return deck_index; return deck_index;
} }
} }
#ifdef YGOPRO_SERVER_MODE
void Reset();
#else
bool OpenReplay(const wchar_t* name); bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]); bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data); bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header); void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length); bool ReadData(void* data, size_t length);
template<typename T> template<typename T>
T Read() { T Read() {
...@@ -91,13 +105,14 @@ public: ...@@ -91,13 +105,14 @@ public:
void Reset(); void Reset();
void SkipInfo(); void SkipInfo();
bool IsReplaying() const; bool IsReplaying() const;
#endif // YGOPRO_SERVER_MODE
FILE* fp{ nullptr }; FILE* fp{ nullptr };
#ifdef _WIN32 #ifdef _WIN32
HANDLE recording_fp{ nullptr }; HANDLE recording_fp{ nullptr };
#endif #endif
ReplayHeader pheader; ExtendedReplayHeader pheader;
unsigned char* comp_data; unsigned char* comp_data;
size_t comp_size{}; size_t comp_size{};
...@@ -108,7 +123,9 @@ public: ...@@ -108,7 +123,9 @@ public:
std::string script_name; // 2 bytes, script name (max: 256 bytes) std::string script_name; // 2 bytes, script name (max: 256 bytes)
private: private:
#ifndef YGOPRO_SERVER_MODE
bool ReadInfo(); bool ReadInfo();
#endif
unsigned char* replay_data; unsigned char* replay_data;
size_t replay_size{}; size_t replay_size{};
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include "duelclient.h" #include "duelclient.h"
#include "game.h" #include "game.h"
#include "data_manager.h" #include "data_manager.h"
#include "../ocgcore/mtrandom.h" #include <random>
#include <thread> #include <thread>
namespace ygo { namespace ygo {
...@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() { ...@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result; return result;
} }
int ReplayMode::ReplayThread() { int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader; const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear(); mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true; mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG); mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
...@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() { ...@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0; return 0;
} }
bool ReplayMode::StartDuel() { bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader; const auto& rh = cur_replay.pheader.base;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
cur_replay.SkipInfo(); cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) { if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
...@@ -168,7 +166,26 @@ bool ReplayMode::StartDuel() { ...@@ -168,7 +166,26 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname); BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname); BufferIO::CopyWideString(cur_replay.players[1].c_str(), mainGame->dInfo.clientname);
} }
pduel = create_duel(rnd()); if(rh.id == REPLAY_ID_YRP1) {
std::mt19937 rnd(rh.seed);
pduel = create_duel(rnd());
} else {
pduel = create_duel_v2(cur_replay.pheader.seed_sequence);
}
mainGame->InjectEnvToRegistry(pduel);
set_registry_value(pduel, "duel_mode", rh.flag & REPLAY_TAG ? "tag" : "single");
set_registry_value(pduel, "start_lp", std::to_string(cur_replay.params.start_lp).c_str());
set_registry_value(pduel, "start_hand", std::to_string(cur_replay.params.start_hand).c_str());
set_registry_value(pduel, "draw_count", std::to_string(cur_replay.params.draw_count).c_str());
char player_name_buf_u[40];
char player_key_buf[23];
for(int i = 0; i < ((rh.flag & REPLAY_TAG) ? 4 : 2); ++i) {
BufferIO::EncodeUTF8(cur_replay.players[i].c_str(), player_name_buf_u);
std::snprintf(player_key_buf, sizeof(player_key_buf), "player_name_%d", i);
set_registry_value(pduel, player_key_buf, player_name_buf_u);
std::snprintf(player_key_buf, sizeof(player_key_buf), "player_type_%d", i);
set_registry_value(pduel, player_key_buf, std::to_string(i).c_str());
}
mainGame->dInfo.duel_rule = cur_replay.params.duel_flag >> 16; mainGame->dInfo.duel_rule = cur_replay.params.duel_flag >> 16;
set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count); set_player_info(pduel, 0, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count); set_player_info(pduel, 1, cur_replay.params.start_lp, cur_replay.params.start_hand, cur_replay.params.draw_count);
...@@ -216,8 +233,6 @@ bool ReplayMode::StartDuel() { ...@@ -216,8 +233,6 @@ bool ReplayMode::StartDuel() {
return false; return false;
} }
} }
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag); start_duel(pduel, cur_replay.params.duel_flag);
return true; return true;
} }
...@@ -417,7 +432,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -417,7 +432,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: { case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf); player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13; pbuf += 9 + count * 14;
return ReadReplayResponse(); return ReadReplayResponse();
} }
case MSG_SELECT_PLACE: case MSG_SELECT_PLACE:
...@@ -470,6 +485,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -470,6 +485,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
} }
case MSG_CONFIRM_CARDS: { case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf); player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7; pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset); DuelClient::ClientAnalyze(offset, pbuf - offset);
......
This diff is collapsed.
...@@ -70,10 +70,11 @@ protected: ...@@ -70,10 +70,11 @@ protected:
unsigned char last_response{ 0 }; unsigned char last_response{ 0 };
std::set<DuelPlayer*> observers; std::set<DuelPlayer*> observers;
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
DuelPlayer* cache_recorder; DuelPlayer* cache_recorder{};
DuelPlayer* replay_recorder; DuelPlayer* replay_recorder{};
unsigned char turn_player; unsigned char turn_player{ 0 };
unsigned short phase; unsigned short phase{ 0 };
bool deck_reversed{ false };
#endif #endif
Replay last_replay; Replay last_replay;
bool match_mode{ false }; bool match_mode{ false };
...@@ -88,9 +89,9 @@ protected: ...@@ -88,9 +89,9 @@ protected:
short time_limit[2]{}; short time_limit[2]{};
short time_elapsed{ 0 }; short time_elapsed{ 0 };
#ifdef YGOPRO_SERVER_MODE #ifdef YGOPRO_SERVER_MODE
short time_compensator[2]; short time_compensator[2]{};
short time_backed[2]; short time_backed[2]{};
unsigned char last_game_msg; unsigned char last_game_msg{ 0 };
#endif #endif
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include "duelclient.h" #include "duelclient.h"
#include "game.h" #include "game.h"
#include "data_manager.h" #include "data_manager.h"
#include "../ocgcore/mtrandom.h" #include <random>
#include <thread> #include <thread>
namespace ygo { namespace ygo {
...@@ -36,12 +36,23 @@ int SingleMode::SinglePlayThread() { ...@@ -36,12 +36,23 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear(); mainGame->dInfo.Clear();
int opt = 0; int opt = 0;
std::random_device rd; std::random_device rd;
unsigned int seed = rd(); ExtendedReplayHeader rh;
mt19937 rnd((uint_fast32_t)seed); rh.base.id = REPLAY_ID_YRP2;
rh.base.version = PRO_VERSION;
rh.base.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.base.start_time = (uint32_t)std::time(nullptr);
for (auto& x : rh.seed_sequence)
x = rd();
std::seed_seq seed(rh.seed_sequence, rh.seed_sequence + SEED_COUNT);
std::mt19937 rnd(seed);
uint32_t duel_seed[SEED_COUNT]{};
for (auto& x : duel_seed)
x = rnd();
set_script_reader(DataManager::ScriptReaderEx); set_script_reader(DataManager::ScriptReaderEx);
set_card_reader(DataManager::CardReader); set_card_reader(DataManager::CardReader);
set_message_handler(SingleMode::MessageHandler); set_message_handler(SingleMode::MessageHandler);
pduel = create_duel(rnd.rand()); pduel = create_duel_v2(duel_seed);
mainGame->InjectEnvToRegistry(pduel);
set_player_info(pduel, 0, start_lp, start_hand, draw_count); set_player_info(pduel, 0, start_lp, start_hand, draw_count);
set_player_info(pduel, 1, start_lp, start_hand, draw_count); set_player_info(pduel, 1, start_lp, start_hand, draw_count);
preload_script(pduel, "./script/special.lua"); preload_script(pduel, "./script/special.lua");
...@@ -82,12 +93,6 @@ int SingleMode::SinglePlayThread() { ...@@ -82,12 +93,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel); end_duel(pduel);
return 0; return 0;
} }
ReplayHeader rh;
rh.id = 0x31707279;
rh.version = PRO_VERSION;
rh.flag = REPLAY_UNIFORM | REPLAY_SINGLE_MODE;
rh.seed = seed;
rh.start_time = (unsigned int)std::time(nullptr);
mainGame->gMutex.lock(); mainGame->gMutex.lock();
mainGame->HideElement(mainGame->wSinglePlay); mainGame->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo(); mainGame->ClearCardInfo();
...@@ -311,7 +316,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -311,7 +316,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: { case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf); player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13; pbuf += 9 + count * 14;
if(!DuelClient::ClientAnalyze(offset, pbuf - offset)) { if(!DuelClient::ClientAnalyze(offset, pbuf - offset)) {
mainGame->singleSignal.Reset(); mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait(); mainGame->singleSignal.Wait();
...@@ -388,6 +393,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -388,6 +393,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
} }
case MSG_CONFIRM_CARDS: { case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf); player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf); count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7; pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset); DuelClient::ClientAnalyze(offset, pbuf - offset);
...@@ -761,7 +767,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -761,7 +767,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
break; break;
} }
case MSG_AI_NAME: { case MSG_AI_NAME: {
char namebuf[128]{}; char namebuf[SIZE_AI_NAME]{};
wchar_t wname[20]{}; wchar_t wname[20]{};
int name_len = buffer_read<uint16_t>(pbuf); int name_len = buffer_read<uint16_t>(pbuf);
if (name_len + 1 <= (int)sizeof namebuf) { if (name_len + 1 <= (int)sizeof namebuf) {
...@@ -774,8 +780,8 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) { ...@@ -774,8 +780,8 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
break; break;
} }
case MSG_SHOW_HINT: { case MSG_SHOW_HINT: {
char msgbuf[1024]{}; char msgbuf[SIZE_HINT_MSG]{};
wchar_t msg[1024]{}; wchar_t msg[SIZE_HINT_MSG]{};
int msg_len = buffer_read<uint16_t>(pbuf); int msg_len = buffer_read<uint16_t>(pbuf);
if (msg_len + 1 <= (int)sizeof msgbuf) { if (msg_len + 1 <= (int)sizeof msgbuf) {
std::memcpy(msgbuf, pbuf, msg_len); std::memcpy(msgbuf, pbuf, msg_len);
......
...@@ -14,11 +14,8 @@ SoundManager soundManager; ...@@ -14,11 +14,8 @@ SoundManager soundManager;
bool SoundManager::Init() { bool SoundManager::Init() {
#ifdef YGOPRO_USE_AUDIO #ifdef YGOPRO_USE_AUDIO
bgm_scene = -1;
previous_bgm_scene = -1;
RefreshBGMList(); RefreshBGMList();
bgm_process = false; rnd.seed(std::random_device()());
rnd.reset((unsigned int)std::time(nullptr));
#ifdef YGOPRO_USE_MINIAUDIO #ifdef YGOPRO_USE_MINIAUDIO
engineConfig = ma_engine_config_init(); engineConfig = ma_engine_config_init();
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS #ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
...@@ -71,6 +68,7 @@ void SoundManager::RefreshBGMList() { ...@@ -71,6 +68,7 @@ void SoundManager::RefreshBGMList() {
#endif #endif
} }
void SoundManager::RefershBGMDir(std::wstring path, int scene) { void SoundManager::RefershBGMDir(std::wstring path, int scene) {
#ifdef YGOPRO_USE_AUDIO
std::wstring search = L"./sound/BGM/" + path; std::wstring search = L"./sound/BGM/" + path;
FileSystem::TraversalDir(search.c_str(), [this, &path, scene](const wchar_t* name, bool isdir) { FileSystem::TraversalDir(search.c_str(), [this, &path, scene](const wchar_t* name, bool isdir) {
if(!isdir && ( if(!isdir && (
...@@ -84,6 +82,7 @@ void SoundManager::RefershBGMDir(std::wstring path, int scene) { ...@@ -84,6 +82,7 @@ void SoundManager::RefershBGMDir(std::wstring path, int scene) {
BGMList[scene].push_back(filename); BGMList[scene].push_back(filename);
} }
}); });
#endif // YGOPRO_USE_AUDIO
} }
void SoundManager::PlaySound(wchar_t* sound) { void SoundManager::PlaySound(wchar_t* sound) {
#ifdef YGOPRO_USE_AUDIO #ifdef YGOPRO_USE_AUDIO
...@@ -254,8 +253,10 @@ void SoundManager::PlaySoundEffect(int sound) { ...@@ -254,8 +253,10 @@ void SoundManager::PlaySoundEffect(int sound) {
default: default:
break; break;
} }
wchar_t soundNameW[32];
BufferIO::DecodeUTF8(soundName, soundNameW);
wchar_t soundPathW[40]; wchar_t soundPathW[40];
myswprintf(soundPathW, L"./sound/%s.wav", soundName); myswprintf(soundPathW, L"./sound/%ls.wav", soundNameW);
PlaySound(soundPathW); PlaySound(soundPathW);
#endif // YGOPRO_USE_AUDIO #endif // YGOPRO_USE_AUDIO
} }
...@@ -335,7 +336,7 @@ void SoundManager::PlayBGM(int scene) { ...@@ -335,7 +336,7 @@ void SoundManager::PlayBGM(int scene) {
if(count <= 0) if(count <= 0)
return; return;
bgm_scene = scene; bgm_scene = scene;
int bgm = rnd.get_random_integer(0, count -1); int bgm = (count > 1) ? std::uniform_int_distribution<>(0, count - 1)(rnd) : 0;
auto name = BGMList[scene][bgm].c_str(); auto name = BGMList[scene][bgm].c_str();
wchar_t BGMName[1024]; wchar_t BGMName[1024];
myswprintf(BGMName, L"./sound/BGM/%ls", name); myswprintf(BGMName, L"./sound/BGM/%ls", name);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define SOUNDMANAGER_H #define SOUNDMANAGER_H
#include "game.h" #include "game.h"
#include "../ocgcore/mtrandom.h" #include <random>
#ifdef YGOPRO_USE_MINIAUDIO #ifdef YGOPRO_USE_MINIAUDIO
#include <miniaudio.h> #include <miniaudio.h>
#endif #endif
...@@ -15,10 +15,10 @@ namespace ygo { ...@@ -15,10 +15,10 @@ namespace ygo {
class SoundManager { class SoundManager {
private: private:
std::vector<std::wstring> BGMList[9]; std::vector<std::wstring> BGMList[9];
int bgm_scene{}; int bgm_scene{ -1 };
int previous_bgm_scene{}; int previous_bgm_scene{ -1 };
bool bgm_process; bool bgm_process { false };
mt19937 rnd; std::mt19937 rnd;
#ifdef YGOPRO_USE_MINIAUDIO #ifdef YGOPRO_USE_MINIAUDIO
ma_engine_config engineConfig; ma_engine_config engineConfig;
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS #ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
......
This diff is collapsed.
This diff is collapsed.
Subproject commit ab7ef30f678a7356e0fca85b0091fcdf56581b35 Subproject commit 326c22e9bd5af2e0f295eb263c095584342db952
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Subproject commit 52007f6939ec3b27238ff705e5364d6e6984e033 Subproject commit 49961747bbe53583deb08f969451805851a96919
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment