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
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
cp -rf ./ygopro-database/locales/$TARGET_LOCALE/strings.conf .
cp -rf ./ygopro-database/locales/$TARGET_LOCALE/servers.conf .
rm -f cards.cdb
sqlite3 ./ygopro-database/locales/$TARGET_LOCALE/cards.cdb .dump | sqlite3 cards.cdb
# 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
TARGET_PLATFORM=$(arch)
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
export OPUS_INCLUDE_DIR=$PWD/miniaudio/external-built/include/opus
export OPUS_LIB_DIR=$PWD/miniaudio/external-built/lib
export OPUSFILE_INCLUDE_DIR=$PWD/miniaudio/external-built/include/opus
export OPUSFILE_LIB_DIR=$PWD/miniaudio/external-built/lib
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
./.ci/configure-audio.sh
rm -rf sqlite3/VERSION sqlite3/version
./premake5 gmake --cc=clang
cd build
make config=release -j$(sysctl -n hw.ncpu)
cd ..
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
# 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 @@
set -x
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
TARGET_PLATFORM=linux
......
......@@ -2,7 +2,7 @@
set -x
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
# ARCHIVE_SUFFIX
......
......@@ -2,7 +2,7 @@
set -x
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
TARGET_PLATFORM=darwin
......
......@@ -2,7 +2,7 @@
set -x
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
# ARCHIVE_SUFFIX
......
......@@ -2,7 +2,7 @@
set -x
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
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
......@@ -2,7 +2,7 @@
set -x
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
TARGET_PLATFORM=win32
......
......@@ -2,7 +2,7 @@
set -x
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
ARCHIVE_FILES=("${ARCHIVE_FILES[@]}" update-koishipro)
......
#!/bin/bash
set -x
set -o errexit
source .ci/asset-branch
IRRLICHT_REPO_URL="https://code.moenext.com/mycard/irrlicht-new.git"
IRRLICHT_BRANCH_NAME="$ASSET_BRANCH_NAME"
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
source .ci/prepare-repo
prepare_repo "https://code.moenext.com/mycard/irrlicht-new.git" "irrlicht"
#!/bin/sh
#!/bin/bash
set -x
set -o errexit
if [ ! -d "miniaudio" ]; then
git clone --depth=1 --branch 0.11.22 https://github.com/mackron/miniaudio
fi
source .ci/prepare-repo
prepare_repo "https://code.moenext.com/mycard/miniaudio.git" "miniaudio"
cp -rf miniaudio/extras/miniaudio_split/miniaudio.* miniaudio/
......@@ -20,7 +19,7 @@ install_external() {
fi
}
install_external "ogg" "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 "opusfile" "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 "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://mat-cacher.moenext.com/https://github.com/xiph/opus/releases/download/v1.5.2/opus-1.5.2.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://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:
- linux
script:
# lua
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/lua-5.4.4.tar.gz | tar zfx -
- mv lua-5.4.4 lua
- wget -O - https://mat-cacher.moenext.com/https://www.lua.org/ftp/lua-5.4.8.tar.gz | tar zfx -
- mv lua-5.4.8 lua
# sqlite3
- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/sqlite-autoconf-3390300.tar.gz | tar zfx -
- mv sqlite-autoconf-3390300 sqlite3
- wget -O - https://mat-cacher.moenext.com/https://www.sqlite.org/2025/sqlite-autoconf-3500100.tar.gz | tar zfx -
- mv sqlite-autoconf-3500100 sqlite3
# freetype
#- wget -O - https://cdn02.moecube.com:444/ygopro-build-materials/freetype-2.11.1.tar.gz | tar zfx -
#- mv freetype-2.11.1 freetype
# - wget -O - https://mat-cacher.moenext.com/https://downloads.sourceforge.net/freetype/freetype-2.13.3.tar.gz | tar zfx -
# - 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
- ./.ci/prepare-irrlicht.sh
# miniaudio
......@@ -33,6 +36,7 @@ mat_common:
- lua
#- freetype
- sqlite3
- event
- irrlicht
#- miniaudio
......@@ -68,7 +72,7 @@ mat_macos:
- linux
script:
- 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
artifacts:
paths:
......@@ -81,25 +85,21 @@ mat_windows:
script:
- apt update; apt -y install wget tar patch p7zip-full
# premake5.exe
- wget https://cdn02.moecube.com:444/ygopro-build-materials/premake-5.0.0-beta5-windows.zip
- 7z x -y premake-5.0.0-beta5-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
- wget https://cdn02.moecube.com:444/premake5-built/premake-5.0.0-beta7-windows.zip
- 7z x -y premake-5.0.0-beta7-windows.zip
artifacts:
paths:
- premake5.exe
- event
._exec_build:
stage: build
#variables:
# NO_LUA_SAFE: '1' # on client no lua safe
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- bin/
- obj/
#cache:
# key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
# paths:
# - bin/
# - obj/
.exec_windows:
extends: ._exec_build
......@@ -119,19 +119,19 @@ exec_windows:
extends: .exec_windows
script:
- '.\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\windows
- copy bin\release\ygopro.exe dist\windows\ygopro.exe
- copy bin\release\x64\ygopro.exe dist\windows\ygopro.exe
exec_windows_pro3:
extends: .exec_windows
script:
- '.\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\windows
- copy bin\release\ygoserver.dll dist\windows\ygoserver.dll
- copy bin\release\x64\ygoserver.dll dist\windows\ygoserver.dll
.exec_unix_common:
extends: ._exec_build
......@@ -140,6 +140,7 @@ exec_windows_pro3:
TARGET_FILE: ygopro
PREMAKE5_BIN: premake5
script:
- ./.ci/configure-libevent.sh
- $PREMAKE5_BIN gmake
- cd build
- make config=release -j$(nproc)
......@@ -169,8 +170,6 @@ exec_windows_pro3:
variables:
BUILD_SQLITE: '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
.exec_debian:
......@@ -182,31 +181,35 @@ exec_windows_pro3:
- apt update; apt -y install git build-essential liblua5.4-dev libsqlite3-dev libevent-dev
.use_arm:
image: git-registry.moenext.com/mycard/docker-ygopro-builder:fpic
tags:
- arm
.use_pro3:
image: git-registry.moenext.com/mycard/docker-ygopro-builder:fpic
variables:
SERVER_PRO3_SUPPORT: '1'
LOG_IN_CHAT: '1'
.use_pro3_linux:
extends: .use_pro3
variables:
TARGET_FILE: libygoserver.so
.use_pro3_macos:
extends: .use_pro3
variables:
SERVER_PRO3_SUPPORT: '1'
LOG_IN_CHAT: '1'
TARGET_FILE: libygoserver.dylib
LIBEVENT_PREBUILD_FLAGS: '-fPIC'
exec_linux:
extends: .exec_linux
tags:
- noavx2
exec_linux_pro3:
extends:
- .exec_linux
- .use_pro3
- .use_pro3_linux
tags:
- avx2
exec_debian:
extends: .exec_debian
......@@ -222,7 +225,7 @@ exec_linuxarm_pro3:
extends:
- .exec_linux
- .use_arm
- .use_pro3
- .use_pro3_linux
variables:
RELEASE_DIR: linux-arm64
......@@ -240,14 +243,13 @@ exec_debianarm:
- mat_common
- mat_macos
- mat_submodules
before_script:
- env CFLAGS=$LIBEVENT_PREBUILD_FLAGS CXXFLAGS=$LIBEVENT_PREBUILD_FLAGS ./.ci/libevent-prebuild.sh
variables:
PREMAKE5_BIN: ./premake5
BUILD_SQLITE: '1'
BUILD_EVENT: '1'
SERVER_ZIP_SUPPORT: '1'
EVENT_INCLUDE_DIR: ../libevent-stable/include
EVENT_LIB_DIR: ../libevent-stable/lib
before_script:
- rm -rf sqlite3/VERSION sqlite3/version
exec_macos_x64:
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}'
image: Visual Studio 2019
image: Visual Studio 2022
skip_tags: true
......@@ -7,37 +7,37 @@ install:
- git submodule update --init --recursive
# 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"
- 7z x premake-5.0.0-beta5-windows.zip
- 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-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"
- tar xf libevent-2.0.22-stable.tar.gz
- move libevent-2.0.22-stable event
- xcopy /E event\WIN32-Code event\include
- 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.1.12-stable.tar.gz
- move libevent-2.1.12-stable event
- 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"
- tar xf lua-5.4.4.tar.gz
- move lua-5.4.4 lua
- 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.7.tar.gz
- 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"
- 7z x sqlite-amalgamation-3470000.zip
- move sqlite-amalgamation-3470000 sqlite3
- 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-3490100.zip
- 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:
- xcopy /E premake\* .
- xcopy /E resource\* .
- premake5 vs2019 --server-zip-support
- premake5 vs2022
configuration: Release
platform: x64
build:
project: build/YGOPro.sln
parallel: true
after_build:
- ps: move bin\release\ygopro.exe .
- ps: move bin\release\x64\ygopro.exe .
# 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"
......@@ -90,8 +90,7 @@ deploy:
branch: server
cache:
- premake-5.0.0-beta2-windows.zip
- libevent-2.0.22-stable.tar.gz
- irrlicht-1.8.5.zip
- lua-5.4.4.tar.gz
- sqlite-amalgamation-3390300.zip
- premake-5.0.0-beta6-windows.zip
- libevent-2.1.12-stable.tar.gz
- lua-5.4.7.tar.gz
- sqlite-amalgamation-3490100.zip
......@@ -28,6 +28,7 @@
john@suckerfreegames.com
*/
#define _IRR_STATIC_LIB_
#include <irrlicht.h>
#include "CGUITTFont.h"
......
......@@ -6,7 +6,6 @@
#include "image_manager.h"
#include "game.h"
#include "materials.h"
#include "../ocgcore/common.h"
namespace ygo {
......@@ -15,7 +14,7 @@ ClientField::ClientField() {
mzone[p].resize(7, 0);
szone[p].resize(8, 0);
}
rnd.reset((uint_fast32_t)std::random_device()());
rnd.seed(std::random_device()());
}
ClientField::~ClientField() {
for (int i = 0; i < 2; ++i) {
......@@ -229,12 +228,12 @@ void ClientField::AddCard(ClientCard* pcard, int controler, int location, int se
}
case LOCATION_GRAVE: {
grave[controler].push_back(pcard);
ResetSequence(grave[controler], false);
pcard->sequence = (unsigned char)(grave[controler].size() - 1);
break;
}
case LOCATION_REMOVED: {
remove[controler].push_back(pcard);
ResetSequence(remove[controler], false);
pcard->sequence = (unsigned char)(remove[controler].size() - 1);
break;
}
case LOCATION_EXTRA: {
......@@ -257,8 +256,13 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) {
switch (location) {
case LOCATION_DECK: {
pcard = deck[controler][sequence];
deck[controler].erase(deck[controler].begin() + sequence);
ResetSequence(deck[controler], true);
for (size_t i = sequence; i < deck[controler].size() - 1; ++i) {
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;
}
case LOCATION_HAND: {
......@@ -279,20 +283,35 @@ ClientCard* ClientField::RemoveCard(int controler, int location, int sequence) {
}
case LOCATION_GRAVE: {
pcard = grave[controler][sequence];
grave[controler].erase(grave[controler].begin() + sequence);
ResetSequence(grave[controler], true);
for (size_t i = sequence; i < grave[controler].size() - 1; ++i) {
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;
}
case LOCATION_REMOVED: {
pcard = remove[controler][sequence];
remove[controler].erase(remove[controler].begin() + sequence);
ResetSequence(remove[controler], true);
for (size_t i = sequence; i < remove[controler].size() - 1; ++i) {
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;
}
case LOCATION_EXTRA: {
pcard = extra[controler][sequence];
extra[controler].erase(extra[controler].begin() + sequence);
ResetSequence(extra[controler], true);
for (size_t i = sequence; i < extra[controler].size() - 1; ++i) {
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)
extra_p_count[controler]--;
break;
......@@ -418,7 +437,7 @@ void ClientField::ShowSelectCard(bool buttonok, bool chain) {
}
}
if(has_card_in_grave) {
rnd.shuffle_vector(selectable_cards);
std::shuffle(selectable_cards.begin(), selectable_cards.end(), rnd);
}
}
int startpos;
......@@ -1163,6 +1182,14 @@ bool ClientField::ShowSelectSum(bool panelmode) {
}
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() {
std::set<ClientCard*> selable;
for(auto sc : selectsum_all) {
......@@ -1203,8 +1230,8 @@ bool ClientField::CheckSelectSum() {
int mm = -1, mx = -1, max = 0, sumc = 0;
bool ret = false;
for (auto sc : selected_cards) {
int op1 = sc->opParam & 0xffff;
int op2 = sc->opParam >> 16;
int op1, op2;
get_sum_params(sc->opParam, op1, op2);
int opmin = (op2 > 0 && op1 > op2) ? op2 : op1;
int opmax = op2 > op1 ? op2 : op1;
if (mm == -1 || opmin < mm)
......@@ -1219,8 +1246,8 @@ bool ClientField::CheckSelectSum() {
if (select_sumval <= max && select_sumval > max - mx)
ret = true;
for(auto sc : selable) {
int op1 = sc->opParam & 0xffff;
int op2 = sc->opParam >> 16;
int op1, op2;
get_sum_params(sc->opParam, op1, op2);
int m = op1;
int sums = sumc;
sums += m;
......@@ -1286,11 +1313,19 @@ bool ClientField::CheckSelectTribute() {
}
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) {
if (index == left.end())
return false;
int op1 = (*index)->opParam & 0xffff;
int op2 = (*index)->opParam >> 16;
int op1, op2;
get_sum_params((*index)->opParam, op1, op2);
int m = (op2 > 0 && op1 > op2) ? op2 : op1;
if (m >= min && m <= max)
return true;
......@@ -1309,9 +1344,8 @@ bool ClientField::check_sel_sum_s(const std::set<ClientCard*>& left, int index,
check_sel_sum_t(left, acc);
return false;
}
int l = selected_cards[index]->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params(selected_cards[index]->opParam, l1, l2);
bool res1 = false, res2 = false;
res1 = check_sel_sum_s(left, index + 1, acc - l1);
if (l2 > 0)
......@@ -1325,9 +1359,8 @@ void ClientField::check_sel_sum_t(const std::set<ClientCard*>& left, int acc) {
continue;
std::set<ClientCard*> testlist(left);
testlist.erase(*sit);
int l = (*sit)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*sit)->opParam, l1, l2);
if (check_sum(testlist.begin(), testlist.end(), acc - l1, count)
|| (l2 > 0 && check_sum(testlist.begin(), testlist.end(), acc - l2, count))) {
selectsum_cards.insert(*sit);
......@@ -1339,9 +1372,8 @@ bool ClientField::check_sum(std::set<ClientCard*>::const_iterator index, std::se
return count >= select_min && count <= select_max;
if (acc < 0 || index == end)
return false;
int l = (*index)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*index)->opParam, l1, l2);
if ((l1 == acc || (l2 > 0 && l2 == acc)) && (count + 1 >= select_min) && (count + 1 <= select_max))
return true;
++index;
......@@ -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);
return acc >= select_min && acc <= select_max;
}
int l = selected_cards[index]->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params(selected_cards[index]->opParam, l1, l2);
bool res1 = false, res2 = false;
res1 = check_sel_sum_trib_s(left, index + 1, acc + l1);
if(l2 > 0)
......@@ -1371,9 +1402,8 @@ void ClientField::check_sel_sum_trib_t(const std::set<ClientCard*>& left, int ac
continue;
std::set<ClientCard*> testlist(left);
testlist.erase(*sit);
int l = (*sit)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*sit)->opParam, l1, l2);
if(check_sum_trib(testlist.begin(), testlist.end(), acc + l1)
|| (l2 > 0 && check_sum_trib(testlist.begin(), testlist.end(), acc + l2))) {
selectsum_cards.insert(*sit);
......@@ -1385,9 +1415,8 @@ bool ClientField::check_sum_trib(std::set<ClientCard*>::const_iterator index, st
return true;
if(acc > select_max || index == end)
return false;
int l = (*index)->opParam;
int l1 = l & 0xffff;
int l2 = l >> 16;
int l1, l2;
get_sum_params((*index)->opParam, l1, l2);
if((acc + l1 >= select_min && acc + l1 <= select_max) || (acc + l2 >= select_min && acc + l2 <= select_max))
return true;
++index;
......
......@@ -2,7 +2,7 @@
#define CLIENT_FIELD_H
#include "config.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <vector>
#include <set>
#include <map>
......@@ -92,7 +92,7 @@ public:
bool cant_check_grave{ false };
bool tag_surrender{ false };
bool tag_teammate_surrender{ false };
mt19937 rnd;
std::mt19937 rnd;
ClientField();
~ClientField();
......@@ -121,6 +121,7 @@ public:
bool ShowSelectSum(bool panelmode);
bool CheckSelectSum();
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_sel_sum_s(const std::set<ClientCard*>& left, int index, int acc);
void check_sel_sum_t(const std::set<ClientCard*>& left, int acc);
......
......@@ -13,7 +13,7 @@
#include <windows.h>
#include <ws2tcpip.h>
#ifdef _MSC_VER
#if defined(_MSC_VER) or defined(__MINGW32__)
#define mywcsncasecmp _wcsnicmp
#define mystrncasecmp _strnicmp
#else
......@@ -52,6 +52,17 @@ inline int _wtoi(const wchar_t * str){
}
#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 <cstdlib>
#include <iostream>
......@@ -105,5 +116,7 @@ extern bool auto_watch_mode;
extern bool open_file;
extern wchar_t open_file_name[256];
extern bool bot_mode;
extern bool expansions_specified;
extern std::vector<std::wstring> expansions_list;
#endif
......@@ -103,12 +103,16 @@ bool DataManager::LoadDB(const wchar_t* wfile) {
else
ret = ReadDB(pDB);
sqlite3_close(pDB);
return ret;
#else
#ifdef _WIN32
auto reader = FileSystem->createAndOpenFile(wfile);
#else
auto reader = FileSystem->createAndOpenFile(file);
#endif
return LoadDB(reader);
}
bool DataManager::LoadDB(irr::io::IReadFile* reader) {
if(reader == nullptr)
return false;
spmemvfs_db_t db;
......@@ -120,14 +124,14 @@ bool DataManager::LoadDB(const wchar_t* wfile) {
reader->drop();
(mem->data)[mem->total] = '\0';
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);
else
ret = ReadDB(db.handle);
spmemvfs_close_db(&db);
spmemvfs_env_fini();
#endif //YGOPRO_SERVER_MODE
return ret;
#endif //SERVER_ZIP_SUPPORT
}
#ifndef YGOPRO_SERVER_MODE
bool DataManager::LoadStrings(const char* file) {
......@@ -141,6 +145,17 @@ bool DataManager::LoadStrings(const char* file) {
std::fclose(fp);
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) {
char ch{};
std::string linebuf;
......@@ -187,10 +202,162 @@ void DataManager::ReadStringConfLine(const char* linebuf) {
_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
bool DataManager::Error(sqlite3* pDB, sqlite3_stmt* pStmt) {
errmsg[0] = '\0';
std::strncat(errmsg, sqlite3_errmsg(pDB), sizeof errmsg - 1);
std::snprintf(errmsg, sizeof errmsg, "%s", sqlite3_errmsg(pDB));
if(pStmt)
sqlite3_finalize(pStmt);
return false;
......@@ -435,19 +602,14 @@ unsigned char* DataManager::ScriptReaderEx(const char* script_name, int* slen) {
buffer = ScriptReaderExSingle("specials/", script_name, slen, 9);
if(buffer)
return buffer;
buffer = ScriptReaderExSingle("expansions/", script_name, slen);
for(auto ex : mainGame->GetExpansionsListU("/")) {
buffer = ScriptReaderExSingle(ex.c_str(), script_name, slen);
if(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);
if(buffer)
return buffer;
#endif
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) {
......
......@@ -45,10 +45,24 @@ public:
DataManager();
bool ReadDB(sqlite3* pDB);
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
bool LoadStrings(const char* file);
bool LoadStrings(const wchar_t* file);
bool LoadStrings(irr::io::IReadFile* reader);
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
bool Error(sqlite3* pDB, sqlite3_stmt* pStmt = nullptr);
......@@ -83,6 +97,7 @@ public:
std::unordered_map<unsigned int, std::wstring> _victoryStrings;
std::unordered_map<unsigned int, std::wstring> _setnameStrings;
std::unordered_map<unsigned int, std::wstring> _sysStrings;
std::vector<std::pair<std::wstring, std::wstring>> _serverStrings;
#endif
char errmsg[512]{};
......@@ -119,6 +134,9 @@ private:
std::unordered_map<unsigned int, CardDataC> _datas;
std::unordered_map<unsigned int, CardString> _strings;
std::unordered_map<unsigned int, std::vector<uint16_t>> extra_setcode;
std::wstring iniName;
std::wstring iniHost;
std::wstring iniPort;
};
extern DataManager dataManager;
......
#include <array>
#include "config.h"
#include "deck_con.h"
#include "myfilesystem.h"
#include "data_manager.h"
#include "deck_manager.h"
#include "image_manager.h"
#include "sound_manager.h"
#include "game.h"
......@@ -54,6 +53,14 @@ static inline void load_current_deck(irr::gui::IGUIComboBox* cbCategory, irr::gu
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() {
mainGame->is_building = true;
mainGame->is_siding = false;
......@@ -82,7 +89,6 @@ void DeckBuilder::Initialize() {
filterList = &deckManager._lfList.back();
}
ClearSearch();
rnd.reset((uint_fast32_t)std::time(nullptr));
mouse_pos.set(0, 0);
hovered_code = 0;
hovered_pos = 0;
......@@ -176,7 +182,7 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
break;
}
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;
}
case BUTTON_SAVE_DECK: {
......@@ -432,6 +438,29 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
prev_operation = id;
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: {
switch(prev_operation) {
case BUTTON_NEW_CATEGORY: {
......@@ -508,7 +537,8 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
}
break;
}
case BUTTON_NEW_DECK: {
case BUTTON_NEW_DECK:
case BUTTON_IMPORT_DECK_CODE: {
const wchar_t* deckname = mainGame->ebDMName->getText();
wchar_t catepath[256];
DeckManager::GetCategoryPath(catepath, mainGame->cbDBCategory->getSelected(), mainGame->cbDBCategory->getText());
......@@ -516,9 +546,19 @@ bool DeckBuilder::OnEvent(const irr::SEvent& event) {
myswprintf(filepath, L"%ls/%ls.ydk", catepath, deckname);
bool res = false;
if(!FileSystem::IsFileExists(filepath)) {
if(prev_operation == BUTTON_NEW_DECK) {
deckManager.current_deck.main.clear();
deckManager.current_deck.extra.clear();
deckManager.current_deck.side.clear();
} else {
const wchar_t* txt = mainGame->env->getOSOperator()->getTextFromClipboard();
if(txt) {
char text[0x10000];
BufferIO::EncodeUTF8(txt, text);
std::istringstream textStream(text);
deckManager.LoadCurrentDeck(textStream);
}
}
res = DeckManager::SaveDeck(deckManager.current_deck, filepath);
RefreshDeckList();
ChangeCategory(mainGame->lstCategories->getSelected());
......
......@@ -3,15 +3,16 @@
#include <unordered_map>
#include <vector>
#include <random>
#include <irrlicht.h>
#include "data_manager.h"
#include "deck_manager.h"
#include "../ocgcore/mtrandom.h"
namespace ygo {
class DeckBuilder: public irr::IEventReceiver {
public:
DeckBuilder();
bool OnEvent(const irr::SEvent& event) override;
void Initialize();
void Terminate();
......@@ -80,7 +81,7 @@ public:
bool is_modified{};
bool readonly{};
bool showing_pack{};
mt19937 rnd;
std::mt19937 rnd;
const LFList* filterList{};
std::vector<code_pointer> results;
......
......@@ -11,53 +11,49 @@ char DeckManager::deckBuffer[0x10000]{};
#endif
DeckManager deckManager;
void DeckManager::LoadLFListSingle(const char* path) {
auto cur = _lfList.rend();
void DeckManager::LoadLFListSingle(const char* path, bool insert) {
FILE* fp = myfopen(path, "r");
char linebuf[256]{};
wchar_t strBuffer[256]{};
char str1[16]{};
if(fp) {
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)));
}
if (!fp) return;
_LoadLFListFromLineProvider([&](char* buf, size_t sz) {
return std::fgets(buf, sz, fp) != nullptr;
}, insert);
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() {
#ifdef SERVER_PRO2_SUPPORT
LoadLFListSingle("config/lflist.conf");
#endif
#ifdef SERVER_PRO3_SUPPORT
LoadLFListSingle("Data/lflist.conf");
#ifndef _WIN32
LoadLFListSingle("Expansions/lflist.conf");
#endif
#endif
LoadLFListSingle("expansions/lflist.conf");
LoadLFListSingle("specials/lflist.conf");
LoadLFListSingle("lflist.conf");
LFList nolimit;
......@@ -299,6 +295,10 @@ irr::io::IReadFile* DeckManager::OpenDeckReader(const wchar_t* file) {
#endif
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) {
current_deck.clear();
auto reader = OpenDeckReader(file);
......@@ -333,21 +333,27 @@ bool DeckManager::LoadCurrentDeck(int category_index, const wchar_t* category_na
mainGame->deckBuilder.RefreshPackListScroll();
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) {
if(!FileSystem::IsDirExists(L"./deck") && !FileSystem::MakeDir(L"./deck"))
return false;
FILE* fp = OpenDeckFile(file, "w");
if(!fp)
return false;
std::fprintf(fp, "#created by ...\n#main\n");
for(size_t i = 0; i < deck.main.size(); ++i)
std::fprintf(fp, "%u\n", deck.main[i]->first);
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::stringstream deckStream;
SaveDeck(deck, deckStream);
std::fwrite(deckStream.str().c_str(), 1, deckStream.str().length(), fp);
std::fclose(fp);
return true;
}
......
......@@ -5,6 +5,7 @@
#include <vector>
#include <sstream>
#include "data_manager.h"
#include "bufferio.h"
#ifndef YGOPRO_MAX_DECK
#define YGOPRO_MAX_DECK 60
......@@ -66,7 +67,11 @@ public:
static char deckBuffer[0x10000];
#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();
const wchar_t* GetLFListName(unsigned int lfhash);
const LFList* GetLFList(unsigned int lfhash);
......@@ -74,11 +79,12 @@ public:
#ifndef YGOPRO_SERVER_MODE
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(std::istringstream& deckStream, bool is_packlist = false);
wchar_t DeckFormatBuffer[128];
int TypeCount(std::vector<code_pointer> list, unsigned int ctype);
bool LoadDeckFromCode(Deck& deck, const unsigned char *code, int len);
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 bool LoadSide(Deck& deck, uint32_t dbuf[], int mainc, int sidec);
......@@ -89,12 +95,56 @@ public:
static FILE* OpenDeckFile(const wchar_t* file, const char* mode);
static irr::io::IReadFile* OpenDeckReader(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 CreateCategory(const wchar_t* name);
static bool RenameCategory(const wchar_t* oldname, const wchar_t* newname);
static bool DeleteCategory(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;
......
......@@ -5,7 +5,6 @@
#include "deck_manager.h"
#include "sound_manager.h"
#include "duelclient.h"
#include "../ocgcore/common.h"
namespace ygo {
......@@ -1393,12 +1392,8 @@ void Game::DrawDeckBd() {
driver->draw2DRectangle(Resize(805, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000);
driver->draw2DRectangleOutline(Resize(804, 159, 1020, 630));
}
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
constexpr int MAX_RESULT = 9;
#else
constexpr int MAX_RESULT = 7;
#endif
for(int i = 0; i < MAX_RESULT && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) {
int max_result = mainGame->gameConf.use_image_load_background_thread ? 9 : 7;
for(int i = 0; i < max_result && i + scrFilter->getPos() < (int)deckBuilder.results.size(); ++i) {
code_pointer ptr = deckBuilder.results[i + scrFilter->getPos()];
if(i >= 7)
{
......
This diff is collapsed.
......@@ -3,8 +3,8 @@
#include <vector>
#include <set>
#include <random>
#include "network.h"
#include "../ocgcore/mtrandom.h"
namespace ygo {
......@@ -65,7 +65,8 @@ private:
static unsigned char last_successful_msg[SIZE_NETWORK_BUFFER];
static size_t last_successful_msg_length;
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 int match_kill;
static event* resp_event;
......@@ -92,7 +93,7 @@ public:
static unsigned int LookupHost(char *host);
static bool LookupSRV(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) {
auto p = duel_client_write;
buffer_write<uint16_t>(p, 1);
......@@ -105,8 +106,7 @@ public:
template<typename ST>
static void SendPacketToServer(unsigned char proto, const ST& st) {
auto p = duel_client_write;
if (sizeof(ST) > MAX_DATA_SIZE)
return;
static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST));
......@@ -128,7 +128,7 @@ public:
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 bool is_srvpro;
static void BeginRefreshHost();
......
#include "event_handler.h"
#include "client_field.h"
#include "math.h"
#include "network.h"
#include "game.h"
#include "duelclient.h"
......@@ -11,7 +10,6 @@
#include "replay_mode.h"
#include "single_mode.h"
#include "materials.h"
#include "../ocgcore/common.h"
namespace ygo {
......@@ -384,9 +382,9 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) {
if (activatable_cards[i] == menu_card) {
if(activatable_descs[i].second == EDESC_OPERATION)
if(activatable_descs[i].second & EDESC_OPERATION)
continue;
else if(activatable_descs[i].second == EDESC_RESET) {
else if(activatable_descs[i].second & EDESC_RESET) {
if(id == BUTTON_CMD_ACTIVATE) continue;
} else {
if(id == BUTTON_CMD_RESET) continue;
......@@ -675,7 +673,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
select_options_index.clear();
for (size_t i = 0; i < activatable_cards.size(); ++i) {
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;
} else {
if(list_command == COMMAND_OPERATION) continue;
......@@ -1322,7 +1320,7 @@ bool ClientField::OnEvent(const irr::SEvent& event) {
case MSG_SELECT_DISFIELD: {
if (!(hovered_location & LOCATION_ONFIELD))
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 & selected_field) {
selected_field &= ~flag;
......
This diff is collapsed.
......@@ -17,10 +17,10 @@
#include "deck_con.h"
#include "menu_handler.h"
#include "CGUISkinSystem/CGUISkinSystem.h"
#include <ctime>
#else
#include "netserver.h"
#endif //YGOPRO_SERVER_MODE
#include <ctime>
#include <unordered_map>
#include <vector>
#include <list>
......@@ -37,18 +37,40 @@ constexpr int TEXT_LINE_SIZE = 256;
namespace ygo {
bool IsExtension(const wchar_t* filename, const wchar_t* extension);
bool IsExtension(const char* filename, const char* extension);
template<size_t N>
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
struct Config {
bool use_d3d{ false };
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 serverport{ 7911 };
unsigned char textfontsize{ 14 };
wchar_t lasthost[100]{};
wchar_t lastport[10]{};
// wchar_t lastport[10]{};
wchar_t nickname[20]{};
wchar_t gamename[20]{};
wchar_t roompass[20]{};
......@@ -172,23 +194,32 @@ public:
#ifdef YGOPRO_SERVER_MODE
void MainServerLoop();
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 initUtils();
void InjectEnvToRegistry(intptr_t pduel);
#else
void MainLoop();
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 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);
void LoadExpansions();
void RefreshCategoryDeck(irr::gui::IGUIComboBox* cbCategory, irr::gui::IGUIComboBox* cbDeck, bool selectlastused = true);
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 RefreshCategoryDeck(irr::gui::IGUIComboBox *cbCategory, irr::gui::IGUIComboBox *cbDeck, bool selectlastused = true);
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 RefreshReplay();
void RefreshSingleplay();
void RefreshBot();
void RefreshLocales();
void RefreshLFList();
void RefreshServerList();
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 DrawBackGround();
......@@ -263,6 +294,7 @@ public:
void FlashWindow();
void takeScreenshot();
void SetCursor(irr::gui::ECURSOR_ICON icon);
void InjectEnvToRegistry(intptr_t pduel);
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,
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:
irr::gui::CGUITTFont* numFont;
irr::gui::CGUITTFont* adFont;
irr::gui::CGUITTFont* lpcFont;
std::map<irr::gui::CGUIImageButton*, int> imageLoading;
std::unordered_map<irr::gui::CGUIImageButton*, int> imageLoading;
//card image
irr::gui::IGUIStaticText* wCardImg;
irr::gui::IGUIImage* imgCard;
......@@ -411,7 +443,6 @@ public:
irr::gui::IGUIListBox* lstHostList;
irr::gui::IGUIButton* btnLanRefresh;
irr::gui::IGUIEditBox* ebJoinHost;
irr::gui::IGUIEditBox* ebJoinPort;
irr::gui::IGUIEditBox* ebJoinPass;
irr::gui::IGUIButton* btnJoinHost;
irr::gui::IGUIButton* btnJoinCancel;
......@@ -616,6 +647,8 @@ public:
irr::gui::IGUIButton* btnDMDeleteDeck;
irr::gui::IGUIButton* btnMoveDeck;
irr::gui::IGUIButton* btnCopyDeck;
irr::gui::IGUIButton* btnImportDeckCode;
irr::gui::IGUIButton* btnExportDeckCode;
irr::gui::IGUIWindow* wDMQuery;
irr::gui::IGUIStaticText* stDMMessage;
irr::gui::IGUIStaticText* stDMMessage2;
......@@ -680,17 +713,25 @@ public:
irr::gui::IGUIButton* btnBigCardZoomIn;
irr::gui::IGUIButton* btnBigCardZoomOut;
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
};
extern Game* mainGame;
#ifdef YGOPRO_SERVER_MODE
#define MAX_MATCH_COUNT 3
extern unsigned short server_port;
extern unsigned short replay_mode;
extern HostInfo game_info;
extern unsigned int pre_seed[5];
extern unsigned int duel_flags;
extern uint32_t pre_seed[MAX_MATCH_COUNT][SEED_COUNT];
extern uint8_t pre_seed_specified[MAX_MATCH_COUNT];
extern uint32_t duel_flags;
#endif
}
......@@ -882,6 +923,8 @@ extern unsigned int duel_flags;
#define LISTBOX_DECKS 340
#define BUTTON_DM_OK 341
#define BUTTON_DM_CANCEL 342
#define BUTTON_IMPORT_DECK_CODE 343
#define BUTTON_EXPORT_DECK_CODE 344
#define COMBOBOX_LFLIST 349
#define BUTTON_CLEAR_LOG 350
......@@ -917,6 +960,10 @@ extern unsigned int duel_flags;
#define BUTTON_DECK_CODE_SAVE 390
#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_DECK 1
#define TEXTURE_MENU 2
......
......@@ -8,8 +8,17 @@
#ifdef __APPLE__
#import <CoreFoundation/CoreFoundation.h>
#endif
#ifdef YGOPRO_SERVER_MODE
#include "base64.h"
#endif
#ifdef YGOPRO_SERVER_MODE
#include <sstream>
#endif
unsigned int enable_log = 0x3;
bool expansions_specified = false;
std::vector<std::wstring> expansions_list;
#ifndef YGOPRO_SERVER_MODE
bool exit_on_return = false;
bool auto_watch_mode = false;
......@@ -72,6 +81,36 @@ int main(int argc, char* argv[]) {
ygo::Game _game;
#ifdef YGOPRO_SERVER_MODE
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::replay_mode = 0;
ygo::duel_flags = 0;
......@@ -85,8 +124,8 @@ int main(int argc, char* argv[]) {
ygo::game_info.no_shuffle_deck = false;
ygo::game_info.duel_rule = YGOPRO_DEFAULT_DUEL_RULE;
ygo::game_info.time_limit = 180;
for (int i = 0; i < 3; ++i)
ygo::pre_seed[i] = (unsigned int)0;
std::memset(ygo::pre_seed, 0, sizeof(ygo::pre_seed));
std::memset(ygo::pre_seed_specified, 0, sizeof(ygo::pre_seed_specified));
if (argc == 2) {
int code = atoi(argv[1]);
ygo::mainGame = &_game;
......@@ -129,9 +168,28 @@ int main(int argc, char* argv[]) {
ygo::game_info.draw_count = atoi(argv[10]);
ygo::game_info.time_limit = atoi(argv[11]);
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;
......@@ -157,7 +215,7 @@ int main(int argc, char* argv[]) {
bool keep_on_return = false;
bool deckCategorySpecified = false;
bool portSpecified = false;
expansions_list.push_back(L"./expansions");
for(int i = 1; i < wargc; ++i) {
if (wargc == 2 && 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[]) {
++i;
if(i < wargc) {
ygo::mainGame->ebJoinHost->setText(wargv[i]);
if(!portSpecified)
ygo::mainGame->ebJoinPort->setText(L"");
}
continue;
} else if(!std::wcscmp(wargv[i], L"-p")) { // host Port
++i;
if(i < wargc) {
portSpecified = true;
auto port = _wtoi(wargv[i]);
if(port) {
wchar_t portStr[6];
myswprintf(portStr, L"%d", port);
ygo::mainGame->ebJoinPort->setText(portStr);
} else {
ygo::mainGame->ebJoinPort->setText(L"");
auto hostText = ygo::mainGame->ebJoinHost->getText();
if(port && hostText) {
wchar_t newHostStr[100];
myswprintf(newHostStr, L"%ls:%d", hostText, port);
ygo::mainGame->ebJoinHost->setText(newHostStr);
}
}
continue;
......@@ -286,6 +340,16 @@ int main(int argc, char* argv[]) {
if(open_file)
ClickButton(ygo::mainGame->btnLoadSinglePlay);
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();
......
This diff is collapsed.
#ifndef IMAGEMANAGER_H
#define IMAGEMANAGER_H
#ifndef _OPENMP
#define YGOPRO_USE_THUMB_LOAD_THREAD
#endif
#include "config.h"
#include "data_manager.h"
#include <unordered_map>
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
#include <queue>
#include <mutex>
#endif
namespace ygo {
......@@ -34,19 +28,15 @@ public:
irr::video::ITexture* GetBigPicture(int code, float zoom);
irr::video::ITexture* GetTextureThumb(int code);
irr::video::ITexture* GetTextureField(int code);
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
static int LoadThumbThread();
#endif
std::unordered_map<int, irr::video::ITexture*> tMap[2];
std::unordered_map<int, irr::video::ITexture*> tThumb;
std::unordered_map<int, irr::video::ITexture*> tFields;
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
std::unordered_map<int, irr::video::IImage*> tThumbLoading;
std::queue<int> tThumbLoadingCodes;
std::mutex tThumbLoadingMutex;
bool tThumbLoadingThreadRunning;
#endif
irr::IrrlichtDevice* device;
irr::video::IVideoDriver* driver;
irr::video::ITexture* tCover[4];
......@@ -54,9 +44,7 @@ public:
irr::video::ITexture* tUnknownFit;
irr::video::ITexture* tUnknownThumb;
irr::video::ITexture* tBigPicture;
#ifdef YGOPRO_USE_THUMB_LOAD_THREAD
irr::video::ITexture* tLoading;
#endif
irr::video::ITexture* tAct;
irr::video::ITexture* tAttack;
irr::video::ITexture* tNegated;
......
......@@ -64,15 +64,11 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_JOIN_HOST: {
bot_mode = false;
mainGame->TrimText(mainGame->ebJoinHost);
mainGame->TrimText(mainGame->ebJoinPort);
char hostname_tag[100];
wchar_t pstr[100];
wchar_t portstr[10];
BufferIO::CopyWideString(mainGame->ebJoinHost->getText(), pstr);
BufferIO::CopyWideString(mainGame->ebJoinPort->getText(), portstr);
BufferIO::EncodeUTF8(pstr, hostname_tag);
auto port = std::wcstol(portstr, nullptr, 10);
HostResult remote = DuelClient::ParseHost(hostname_tag, port);
HostResult remote = DuelClient::ParseHost(hostname_tag);
if(!remote.isValid()) {
mainGame->gMutex.lock();
soundManager.PlaySoundEffect(SOUND_INFO);
......@@ -85,7 +81,6 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break;
}
BufferIO::CopyWideString(pstr, mainGame->gameConf.lasthost);
BufferIO::CopyWideString(portstr, mainGame->gameConf.lastport);
BufferIO::CopyWideString(mainGame->ebJoinPass->getText(), mainGame->gameConf.roompass);
if(DuelClient::StartClient(remote.host, remote.port, false)) {
mainGame->btnCreateHost->setEnabled(false);
......@@ -96,6 +91,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
}
case BUTTON_JOIN_CANCEL: {
mainGame->HideElement(mainGame->wLanWindow);
mainGame->HideElement(mainGame->wServerList);
mainGame->ShowElement(mainGame->wMainMenu);
if(exit_on_return)
mainGame->device->closeDevice();
......@@ -109,6 +105,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->btnHostConfirm->setEnabled(true);
mainGame->btnHostCancel->setEnabled(true);
mainGame->HideElement(mainGame->wLanWindow);
mainGame->HideElement(mainGame->wServerList);
mainGame->ShowElement(mainGame->wCreateHost);
break;
}
......@@ -220,8 +217,12 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
case BUTTON_LOAD_REPLAY: {
int start_turn = 1;
if(open_file) {
ReplayMode::cur_replay.OpenReplay(open_file_name);
open_file = false;
if (!ReplayMode::cur_replay.OpenReplay(open_file_name)) {
if (exit_on_return)
mainGame->device->closeDevice();
break;
}
} else {
auto selected = mainGame->lstReplayList->getSelected();
if(selected == -1)
......@@ -295,7 +296,7 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
myswprintf(replay_path, L"./replay/%ls", replay_filename);
if (!replay.OpenReplay(replay_path))
break;
if (replay.pheader.flag & REPLAY_SINGLE_MODE)
if (replay.pheader.base.flag & REPLAY_SINGLE_MODE)
break;
for (size_t i = 0; i < replay.decks.size(); ++i) {
BufferIO::CopyWideString(replay.players[Replay::GetDeckPlayer(i)].c_str(), namebuf[i]);
......@@ -489,6 +490,15 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
prev_sel = -1;
break;
}
case BUTTON_SERVER_LIST: {
mainGame->ShowElement(mainGame->wServerList);
mainGame->PopupElement(mainGame->wServerList);
break;
}
case BUTTON_SERVER_RETURN: {
mainGame->HideElement(mainGame->wServerList);
break;
}
}
break;
}
......@@ -502,21 +512,18 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
mainGame->ebJoinPass->setText(DuelClient::hosts_srvpro[sel].c_str());
break;
}
int addr = DuelClient::hosts[sel].ipaddr;
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);
mainGame->ebJoinHost->setText(DuelClient::hosts[sel].c_str());
break;
}
case LISTBOX_REPLAY_LIST: {
int sel = mainGame->lstReplayList->getSelected();
if(sel == -1)
if(sel < 0)
break;
auto filename = mainGame->lstReplayList->getListItem(sel);
if (!filename)
break;
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)) {
mainGame->stReplayInfo->setText(L"Error");
break;
......@@ -524,20 +531,25 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
wchar_t infobuf[256]{};
std::wstring repinfo;
time_t curtime;
if(temp_replay.pheader.flag & REPLAY_UNIFORM)
curtime = temp_replay.pheader.start_time;
else
curtime = temp_replay.pheader.seed;
const auto& rh = temp_replay.pheader.base;
if(temp_replay.pheader.base.flag & REPLAY_UNIFORM)
curtime = rh.start_time;
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));
repinfo.append(infobuf);
if (temp_replay.pheader.flag & REPLAY_SINGLE_MODE) {
if (rh.flag & REPLAY_SINGLE_MODE) {
wchar_t path[256]{};
BufferIO::DecodeUTF8(temp_replay.script_name.c_str(), path);
repinfo.append(path);
repinfo.append(L"\n");
}
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());
else
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) {
mainGame->cbBotDeck->setVisible(mainGame->botInfo[sel].select_deckfile);
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;
}
......
......@@ -297,7 +297,11 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
case CTOS_CHAT: {
if(!dp->game)
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;
duel_mode->Chat(dp, pdata, len - 1);
break;
......@@ -344,6 +348,15 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
BufferIO::CopyCharArray(pkt->name, dp->name);
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: {
if(dp->game || duel_mode)
return;
......@@ -424,6 +437,14 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
duel_mode->ToObserver(dp);
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_NOTREADY: {
if (!duel_mode || duel_mode->pduel)
......@@ -431,6 +452,7 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, unsigned char* data, int len) {
duel_mode->PlayerReady(dp, (CTOS_HS_NOTREADY - pktType) != 0);
break;
}
#endif
case CTOS_HS_KICK: {
if (!duel_mode || duel_mode->pduel)
return;
......@@ -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) {
if (!check_msg_size(src_size))
return 0;
uint16_t src_msg[LEN_CHAT_MSG];
std::memcpy(src_msg, src, src_size);
const int src_len = src_size / sizeof(uint16_t);
......
......@@ -58,8 +58,7 @@ public:
template<typename ST>
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, const ST& st) {
auto p = net_server_write;
if (sizeof(ST) > MAX_DATA_SIZE)
return;
static_assert(sizeof(ST) <= MAX_DATA_SIZE, "Packet size is too large.");
buffer_write<uint16_t>(p, (uint16_t)(1 + sizeof(ST)));
buffer_write<uint8_t>(p, proto);
std::memcpy(p, &st, sizeof(ST));
......
......@@ -103,6 +103,14 @@ struct CTOS_Kick {
check_trivially_copyable(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
struct STOC_ErrorMsg {
uint8_t msg{};
......@@ -196,17 +204,6 @@ struct DuelPlayer {
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) {
unsigned int info = 0;
std::memcpy(&info, qbuf + offset, sizeof info);
......@@ -249,6 +246,7 @@ public:
intptr_t pduel{};
wchar_t name[20]{};
wchar_t pass[20]{};
std::vector<byte> registry_dump;
};
}
......@@ -275,6 +273,7 @@ public:
#define CTOS_SURRENDER 0x14 // no data
#define CTOS_TIME_CONFIRM 0x15 // no data
#define CTOS_CHAT 0x16 // uint16_t array
#define CTOS_EXTERNAL_ADDRESS 0x17 // CTOS_ExternalAddress
#define CTOS_HS_TODUELIST 0x20 // no data
#define CTOS_HS_TOOBSERVER 0x21 // no data
#define CTOS_HS_READY 0x22 // no data
......@@ -298,7 +297,7 @@ public:
#define STOC_LEAVE_GAME 0x14 // reserved
#define STOC_DUEL_START 0x15 // 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_CHAT 0x19 // uint16_t + uint16_t array
#define STOC_HS_PLAYER_ENTER 0x20 // STOC_HS_PlayerEnter
......
......@@ -45,7 +45,6 @@ end
else
project "ygopro"
kind "WindowedApp"
cppdialect "C++14"
rtti "Off"
openmp "On"
......@@ -54,11 +53,16 @@ project "ygopro"
links { "ocgcore", "clzma", "cspmemvfs", LUA_LIB_NAME, "sqlite3", "irrlicht", "freetype", "event" }
end
if not BUILD_LUA then
libdirs { LUA_LIB_DIR }
end
if BUILD_EVENT then
includedirs { "../event/include" }
else
includedirs { EVENT_INCLUDE_DIR }
libdirs { EVENT_LIB_DIR }
links { "event_pthreads" }
end
if BUILD_IRRLICHT then
......@@ -82,7 +86,7 @@ end
libdirs { SQLITE_LIB_DIR }
end
if USE_AUDIO then
if USE_AUDIO and not SERVER_MODE then
defines { "YGOPRO_USE_AUDIO" }
if AUDIO_LIB == "miniaudio" then
defines { "YGOPRO_USE_MINIAUDIO" }
......@@ -110,43 +114,53 @@ end
end
filter "system:windows"
entrypoint "mainCRTStartup"
defines { "_IRR_WCHAR_FILESYSTEM" }
files "ygopro.rc"
if SERVER_PRO2_SUPPORT then
targetname ("AI.Server")
end
if SERVER_MODE then
links { "ws2_32" }
links { "ws2_32", "iphlpapi" }
else
links { "opengl32", "ws2_32", "winmm", "gdi32", "kernel32", "user32", "imm32", "Dnsapi" }
links { "ws2_32", "Dnsapi", "iphlpapi" }
end
if USE_AUDIO and AUDIO_LIB == "irrklang" then
links { "irrKlang" }
if IRRKLANG_PRO then
defines { "IRRKLANG_STATIC" }
filter { "not configurations:Debug" }
filter { "system:windows", "not configurations:Debug" }
libdirs { IRRKLANG_PRO_RELEASE_LIB_DIR }
filter { "configurations:Debug" }
filter { "system:windows", "configurations:Debug" }
libdirs { IRRKLANG_PRO_DEBUG_LIB_DIR }
filter {}
end
end
if not SERVER_MODE then
filter "not system:windows"
links { "event_pthreads", "dl", "pthread", "resolv" }
links { "resolv" }
end
filter "not action:vs*"
cppdialect "C++14"
filter "system:macosx"
if not SERVER_MODE then
openmp "Off"
links { "z" }
links { "OpenGL.framework", "Cocoa.framework", "IOKit.framework" }
defines { "GL_SILENCE_DEPRECATION" }
end
if MAC_ARM then
buildoptions { "--target=arm64-apple-macos12" }
linkoptions { "-arch arm64" }
end
if MAC_INTEL then
linkoptions { "-arch x86_64" }
end
if USE_AUDIO and AUDIO_LIB == "irrklang" then
links { "irrklang" }
end
filter "system:linux"
links { "dl", "pthread" }
linkoptions { "-static-libstdc++", "-static-libgcc" }
if not SERVER_MODE then
links { "GL", "X11", "Xxf86vm" }
......
......@@ -48,7 +48,7 @@ void Replay::BeginRecord() {
char tmppath[40];
strftime(tmppath, 40, "./replay/%Y-%m-%d %H-%M-%S %%u.yrp", localedtime);
char path[40];
std::sprintf(path, tmppath, server_port);
sprintf(path, tmppath, server_port);
fp = myfopen(path, "wb");
#else
fp = myfopen("./replay/_LastReplay.yrp", "wb");
......@@ -62,7 +62,7 @@ void Replay::BeginRecord() {
Reset();
is_recording = true;
}
void Replay::WriteHeader(ReplayHeader& header) {
void Replay::WriteHeader(ExtendedReplayHeader& header) {
pheader = header;
#ifdef YGOPRO_SERVER_MODE
if(!(replay_mode & REPLAY_MODE_SAVE_IN_SERVER)) return;
......@@ -122,11 +122,11 @@ void Replay::EndRecord() {
#ifdef YGOPRO_SERVER_MODE
}
#endif
pheader.datasize = replay_size;
pheader.flag |= REPLAY_COMPRESSED;
pheader.base.datasize = replay_size;
pheader.base.flag |= REPLAY_COMPRESSED;
size_t propsize = 5;
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) {
std::memcpy(comp_data, &ret, sizeof ret);
comp_size = sizeof ret;
......@@ -145,6 +145,7 @@ void Replay::SaveReplay(const wchar_t* name) {
std::fwrite(comp_data, comp_size, 1, rfp);
std::fclose(rfp);
}
#ifndef YGOPRO_SERVER_MODE
bool Replay::OpenReplay(const wchar_t* name) {
FILE* rfp = mywfopen(name, "rb");
if(!rfp) {
......@@ -156,19 +157,32 @@ bool Replay::OpenReplay(const wchar_t* name) {
return false;
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);
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);
std::fclose(rfp);
if (pheader.datasize > MAX_REPLAY_SIZE)
if (pheader.base.datasize > MAX_REPLAY_SIZE)
return false;
replay_size = pheader.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.props, 5) != SZ_OK)
replay_size = pheader.base.datasize;
if (LzmaUncompress(replay_data, &replay_size, comp_data, &comp_size, pheader.base.props, 5) != SZ_OK)
return false;
if (replay_size != pheader.datasize) {
if (replay_size != pheader.base.datasize) {
replay_size = 0;
return false;
}
......@@ -187,17 +201,6 @@ bool Replay::OpenReplay(const wchar_t* name) {
data_position = 0;
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) {
wchar_t fname[256];
myswprintf(fname, L"./replay/%ls", name);
......@@ -236,7 +239,7 @@ bool Replay::ReadName(wchar_t* data) {
BufferIO::CopyWStr(buffer, data, 20);
return true;
}
void Replay::ReadHeader(ReplayHeader& header) {
void Replay::ReadHeader(ExtendedReplayHeader& header) {
header = pheader;
}
bool Replay::ReadData(void* data, size_t length) {
......@@ -258,6 +261,7 @@ void Replay::Rewind() {
data_position = 0;
can_read = true;
}
#endif // YGOPRO_SERVER_MODE
void Replay::Reset() {
is_recording = false;
is_replaying = false;
......@@ -271,6 +275,7 @@ void Replay::Reset() {
decks.clear();
script_name.clear();
}
#ifndef YGOPRO_SERVER_MODE
void Replay::SkipInfo(){
if (data_position == 0)
data_position += info_offset;
......@@ -279,7 +284,7 @@ bool Replay::IsReplaying() const {
return is_replaying;
}
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) {
wchar_t name[20]{};
if (!ReadName(name))
......@@ -288,11 +293,11 @@ bool Replay::ReadInfo() {
}
if (!ReadData(&params, sizeof params))
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;
if (is_tag1 != is_tag2)
return false;
if (pheader.flag & REPLAY_SINGLE_MODE) {
if (pheader.base.flag & REPLAY_SINGLE_MODE) {
uint16_t slen = Read<uint16_t>();
char filename[256]{};
if (slen == 0 || slen > sizeof(filename) - 1)
......@@ -328,5 +333,6 @@ bool Replay::ReadInfo() {
}
return true;
}
#endif // YGOPRO_SERVER_MODE
}
......@@ -13,6 +13,9 @@ namespace ygo {
#define REPLAY_SINGLE_MODE 0x8
#define REPLAY_UNIFORM 0x10
#define REPLAY_ID_YRP1 0x31707279
#define REPLAY_ID_YRP2 0x32707279
// max size
constexpr int MAX_REPLAY_SIZE = 0x80000;
constexpr int MAX_COMP_SIZE = UINT16_MAX + 1;
......@@ -36,6 +39,15 @@ struct ReplayHeader {
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 {
int32_t start_lp{};
int32_t start_hand{};
......@@ -50,7 +62,7 @@ public:
// record
void BeginRecord();
void WriteHeader(ReplayHeader& header);
void WriteHeader(ExtendedReplayHeader& header);
void WriteData(const void* data, size_t length, bool flush = true);
template<typename T>
void Write(T data, bool flush = true) {
......@@ -62,7 +74,6 @@ public:
void SaveReplay(const wchar_t* name);
// play
static bool CheckReplay(const wchar_t* name);
static bool DeleteReplay(const wchar_t* name);
static bool RenameReplay(const wchar_t* oldname, const wchar_t* newname);
static size_t GetDeckPlayer(size_t deck_index) {
......@@ -75,10 +86,13 @@ public:
return deck_index;
}
}
#ifdef YGOPRO_SERVER_MODE
void Reset();
#else
bool OpenReplay(const wchar_t* name);
bool ReadNextResponse(unsigned char resp[]);
bool ReadName(wchar_t* data);
void ReadHeader(ReplayHeader& header);
void ReadHeader(ExtendedReplayHeader& header);
bool ReadData(void* data, size_t length);
template<typename T>
T Read() {
......@@ -91,13 +105,14 @@ public:
void Reset();
void SkipInfo();
bool IsReplaying() const;
#endif // YGOPRO_SERVER_MODE
FILE* fp{ nullptr };
#ifdef _WIN32
HANDLE recording_fp{ nullptr };
#endif
ReplayHeader pheader;
ExtendedReplayHeader pheader;
unsigned char* comp_data;
size_t comp_size{};
......@@ -108,7 +123,9 @@ public:
std::string script_name; // 2 bytes, script name (max: 256 bytes)
private:
#ifndef YGOPRO_SERVER_MODE
bool ReadInfo();
#endif
unsigned char* replay_data;
size_t replay_size{};
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -57,7 +57,7 @@ bool ReplayMode::ReadReplayResponse() {
return result;
}
int ReplayMode::ReplayThread() {
const ReplayHeader& rh = cur_replay.pheader;
const auto& rh = cur_replay.pheader.base;
mainGame->dInfo.Clear();
mainGame->dInfo.isFirst = true;
mainGame->dInfo.isTag = !!(rh.flag & REPLAY_TAG);
......@@ -155,9 +155,7 @@ int ReplayMode::ReplayThread() {
return 0;
}
bool ReplayMode::StartDuel() {
const ReplayHeader& rh = cur_replay.pheader;
unsigned int seed = rh.seed;
std::mt19937 rnd(seed);
const auto& rh = cur_replay.pheader.base;
cur_replay.SkipInfo();
if(rh.flag & REPLAY_TAG) {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
......@@ -168,7 +166,26 @@ bool ReplayMode::StartDuel() {
BufferIO::CopyWideString(cur_replay.players[0].c_str(), mainGame->dInfo.hostname);
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());
} 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;
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);
......@@ -216,8 +233,6 @@ bool ReplayMode::StartDuel() {
return false;
}
}
if (!(rh.flag & REPLAY_UNIFORM))
cur_replay.params.duel_flag |= DUEL_OLD_REPLAY;
start_duel(pduel, cur_replay.params.duel_flag);
return true;
}
......@@ -417,7 +432,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
return ReadReplayResponse();
}
case MSG_SELECT_PLACE:
......@@ -470,6 +485,7 @@ bool ReplayMode::ReplayAnalyze(unsigned char* msg, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
......
This diff is collapsed.
......@@ -70,10 +70,11 @@ protected:
unsigned char last_response{ 0 };
std::set<DuelPlayer*> observers;
#ifdef YGOPRO_SERVER_MODE
DuelPlayer* cache_recorder;
DuelPlayer* replay_recorder;
unsigned char turn_player;
unsigned short phase;
DuelPlayer* cache_recorder{};
DuelPlayer* replay_recorder{};
unsigned char turn_player{ 0 };
unsigned short phase{ 0 };
bool deck_reversed{ false };
#endif
Replay last_replay;
bool match_mode{ false };
......@@ -88,9 +89,9 @@ protected:
short time_limit[2]{};
short time_elapsed{ 0 };
#ifdef YGOPRO_SERVER_MODE
short time_compensator[2];
short time_backed[2];
unsigned char last_game_msg;
short time_compensator[2]{};
short time_backed[2]{};
unsigned char last_game_msg{ 0 };
#endif
};
......
......@@ -2,7 +2,7 @@
#include "duelclient.h"
#include "game.h"
#include "data_manager.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#include <thread>
namespace ygo {
......@@ -36,12 +36,23 @@ int SingleMode::SinglePlayThread() {
mainGame->dInfo.Clear();
int opt = 0;
std::random_device rd;
unsigned int seed = rd();
mt19937 rnd((uint_fast32_t)seed);
ExtendedReplayHeader rh;
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_card_reader(DataManager::CardReader);
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, 1, start_lp, start_hand, draw_count);
preload_script(pduel, "./script/special.lua");
......@@ -82,12 +93,6 @@ int SingleMode::SinglePlayThread() {
end_duel(pduel);
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->HideElement(mainGame->wSinglePlay);
mainGame->ClearCardInfo();
......@@ -311,7 +316,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
case MSG_SELECT_CHAIN: {
player = BufferIO::ReadUInt8(pbuf);
count = BufferIO::ReadUInt8(pbuf);
pbuf += 10 + count * 13;
pbuf += 9 + count * 14;
if(!DuelClient::ClientAnalyze(offset, pbuf - offset)) {
mainGame->singleSignal.Reset();
mainGame->singleSignal.Wait();
......@@ -388,6 +393,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
}
case MSG_CONFIRM_CARDS: {
player = BufferIO::ReadUInt8(pbuf);
pbuf += 1;
count = BufferIO::ReadUInt8(pbuf);
pbuf += count * 7;
DuelClient::ClientAnalyze(offset, pbuf - offset);
......@@ -761,7 +767,7 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
break;
}
case MSG_AI_NAME: {
char namebuf[128]{};
char namebuf[SIZE_AI_NAME]{};
wchar_t wname[20]{};
int name_len = buffer_read<uint16_t>(pbuf);
if (name_len + 1 <= (int)sizeof namebuf) {
......@@ -774,8 +780,8 @@ bool SingleMode::SinglePlayAnalyze(unsigned char* msg, unsigned int len) {
break;
}
case MSG_SHOW_HINT: {
char msgbuf[1024]{};
wchar_t msg[1024]{};
char msgbuf[SIZE_HINT_MSG]{};
wchar_t msg[SIZE_HINT_MSG]{};
int msg_len = buffer_read<uint16_t>(pbuf);
if (msg_len + 1 <= (int)sizeof msgbuf) {
std::memcpy(msgbuf, pbuf, msg_len);
......
......@@ -14,11 +14,8 @@ SoundManager soundManager;
bool SoundManager::Init() {
#ifdef YGOPRO_USE_AUDIO
bgm_scene = -1;
previous_bgm_scene = -1;
RefreshBGMList();
bgm_process = false;
rnd.reset((unsigned int)std::time(nullptr));
rnd.seed(std::random_device()());
#ifdef YGOPRO_USE_MINIAUDIO
engineConfig = ma_engine_config_init();
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
......@@ -71,6 +68,7 @@ void SoundManager::RefreshBGMList() {
#endif
}
void SoundManager::RefershBGMDir(std::wstring path, int scene) {
#ifdef YGOPRO_USE_AUDIO
std::wstring search = L"./sound/BGM/" + path;
FileSystem::TraversalDir(search.c_str(), [this, &path, scene](const wchar_t* name, bool isdir) {
if(!isdir && (
......@@ -84,6 +82,7 @@ void SoundManager::RefershBGMDir(std::wstring path, int scene) {
BGMList[scene].push_back(filename);
}
});
#endif // YGOPRO_USE_AUDIO
}
void SoundManager::PlaySound(wchar_t* sound) {
#ifdef YGOPRO_USE_AUDIO
......@@ -254,8 +253,10 @@ void SoundManager::PlaySoundEffect(int sound) {
default:
break;
}
wchar_t soundNameW[32];
BufferIO::DecodeUTF8(soundName, soundNameW);
wchar_t soundPathW[40];
myswprintf(soundPathW, L"./sound/%s.wav", soundName);
myswprintf(soundPathW, L"./sound/%ls.wav", soundNameW);
PlaySound(soundPathW);
#endif // YGOPRO_USE_AUDIO
}
......@@ -335,7 +336,7 @@ void SoundManager::PlayBGM(int scene) {
if(count <= 0)
return;
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();
wchar_t BGMName[1024];
myswprintf(BGMName, L"./sound/BGM/%ls", name);
......
......@@ -2,7 +2,7 @@
#define SOUNDMANAGER_H
#include "game.h"
#include "../ocgcore/mtrandom.h"
#include <random>
#ifdef YGOPRO_USE_MINIAUDIO
#include <miniaudio.h>
#endif
......@@ -15,10 +15,10 @@ namespace ygo {
class SoundManager {
private:
std::vector<std::wstring> BGMList[9];
int bgm_scene{};
int previous_bgm_scene{};
bool bgm_process;
mt19937 rnd;
int bgm_scene{ -1 };
int previous_bgm_scene{ -1 };
bool bgm_process { false };
std::mt19937 rnd;
#ifdef YGOPRO_USE_MINIAUDIO
ma_engine_config engineConfig;
#ifdef YGOPRO_MINIAUDIO_SUPPORT_OPUS_VORBIS
......
This diff is collapsed.
......@@ -66,10 +66,11 @@ protected:
DuelPlayer* cur_player[2];
std::set<DuelPlayer*> observers;
#ifdef YGOPRO_SERVER_MODE
DuelPlayer* cache_recorder;
DuelPlayer* replay_recorder;
int turn_player;
int phase;
DuelPlayer* cache_recorder{};
DuelPlayer* replay_recorder{};
unsigned char turn_player{ 0 };
unsigned short phase{ 0 };
bool deck_reversed{ false };
#endif
bool ready[4];
bool surrender[4];
......@@ -82,13 +83,12 @@ protected:
short time_limit[2];
short time_elapsed;
#ifdef YGOPRO_SERVER_MODE
short time_compensator[2];
short time_backed[2];
unsigned char last_game_msg;
short time_compensator[2]{};
short time_backed[2]{};
unsigned char last_game_msg{ 0 };
#endif
};
}
#endif //TAG_DUEL_H
Subproject commit ab7ef30f678a7356e0fca85b0091fcdf56581b35
Subproject commit 326c22e9bd5af2e0f295eb263c095584342db952
This diff is collapsed.
This diff is collapsed.
......@@ -155,10 +155,11 @@ project "irrlicht"
filter { "system:windows" }
defines { "_IRR_WCHAR_FILESYSTEM" }
if USE_DXSDK then
includedirs { "$(DXSDK_DIR)Include" }
filter { "system:linux" }
links { "X11", "Xxf86vm" }
else
defines { "NO_IRR_COMPILE_WITH_DIRECT3D_9_" }
end
filter { "system:macosx" }
cppdialect "gnu++14"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
1 ICON "ygopro.ico"
1 VERSIONINFO
FILEVERSION 1, 0, 36, 1
PRODUCTVERSION 1, 0, 36, 1
FILEVERSION 1, 0, 36, 2
PRODUCTVERSION 1, 0, 36, 2
FILEOS 0x4
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