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("/")) {
buffer = ScriptReaderExSingle(ex.c_str(), script_name, slen);
if(buffer) if(buffer)
return buffer; return buffer;
#if defined(SERVER_PRO3_SUPPORT) && !defined(_WIN32) }
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)) {
if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.main.clear(); deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear(); deckManager.current_deck.extra.clear();
deckManager.current_deck.side.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)) {
if(linebuf[0] == '#')
continue;
if(linebuf[0] == '!') {
auto len = std::strcspn(linebuf, "\r\n");
linebuf[len] = 0;
BufferIO::DecodeUTF8(&linebuf[1], strBuffer);
LFList newlist;
newlist.listName = strBuffer;
newlist.hash = 0x7dfcee6a;
_lfList.push_back(newlist);
cur = _lfList.rbegin();
continue;
}
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); std::fclose(fp);
}
void DeckManager::LoadLFListSingle(const wchar_t* path, bool insert) {
FILE* fp = mywfopen(path, "r");
if (!fp) return;
_LoadLFListFromLineProvider([&](char* buf, size_t sz) {
return std::fgets(buf, sz, fp) != nullptr;
}, insert);
std::fclose(fp);
}
#if defined(SERVER_ZIP_SUPPORT) || !defined(YGOPRO_SERVER_MODE)
void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader, bool insert) {
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;
} }
}
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);
} }
if(rh.id == REPLAY_ID_YRP1) {
std::mt19937 rnd(rh.seed);
pduel = create_duel(rnd()); 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.
...@@ -66,10 +66,11 @@ protected: ...@@ -66,10 +66,11 @@ protected:
DuelPlayer* cur_player[2]; DuelPlayer* cur_player[2];
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{};
int turn_player; unsigned char turn_player{ 0 };
int phase; unsigned short phase{ 0 };
bool deck_reversed{ false };
#endif #endif
bool ready[4]; bool ready[4];
bool surrender[4]; bool surrender[4];
...@@ -82,13 +83,12 @@ protected: ...@@ -82,13 +83,12 @@ protected:
short time_limit[2]; short time_limit[2];
short time_elapsed; short time_elapsed;
#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
}; };
} }
#endif //TAG_DUEL_H #endif //TAG_DUEL_H
Subproject commit ab7ef30f678a7356e0fca85b0091fcdf56581b35 Subproject commit 326c22e9bd5af2e0f295eb263c095584342db952
This diff is collapsed.
This diff is collapsed.
...@@ -155,10 +155,11 @@ project "irrlicht" ...@@ -155,10 +155,11 @@ project "irrlicht"
filter { "system:windows" } filter { "system:windows" }
defines { "_IRR_WCHAR_FILESYSTEM" } defines { "_IRR_WCHAR_FILESYSTEM" }
if USE_DXSDK then
includedirs { "$(DXSDK_DIR)Include" } includedirs { "$(DXSDK_DIR)Include" }
else
filter { "system:linux" } defines { "NO_IRR_COMPILE_WITH_DIRECT3D_9_" }
links { "X11", "Xxf86vm" } end
filter { "system:macosx" } filter { "system:macosx" }
cppdialect "gnu++14" cppdialect "gnu++14"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
1 ICON "ygopro.ico" 1 ICON "ygopro.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 1, 0, 36, 1 FILEVERSION 1, 0, 36, 2
PRODUCTVERSION 1, 0, 36, 1 PRODUCTVERSION 1, 0, 36, 2
FILEOS 0x4 FILEOS 0x4
FILETYPE 0x1 FILETYPE 0x1
......
This diff is collapsed.
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