Compare commits
49 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
717d4eb5c6 | ||
|
|
6fd8d12386 | ||
|
|
6ffd04038c | ||
|
|
7a648a8aeb | ||
|
|
14c7885f58 | ||
|
|
1ec04251e8 | ||
|
|
d7b1e68b21 | ||
|
|
cbfafdb63f | ||
|
|
6fcbbb6edb | ||
|
|
0170bca4c0 | ||
|
|
359e3c3dc8 | ||
|
|
bc7b6f9b9f | ||
|
|
d20015de69 | ||
|
|
09344d58a4 | ||
|
|
30f58ed436 | ||
|
|
ba112425f8 | ||
|
|
f2a0ba443e | ||
|
|
cc1c8d7950 | ||
|
|
ef8c54c195 | ||
|
|
bc428260fa | ||
|
|
5391c665ac | ||
|
|
c4bbe512df | ||
|
|
a67cf3deaa | ||
|
|
44c15ab011 | ||
|
|
8d35663f3d | ||
|
|
d8cee80266 | ||
|
|
724ebbda99 | ||
|
|
8f08c3b817 | ||
|
|
4bddb5bd0a | ||
|
|
2ef28aae5f | ||
|
|
51c456e907 | ||
|
|
afa42fe498 | ||
|
|
a79f7c8fcc | ||
|
|
ef9b79f120 | ||
|
|
553ed365e9 | ||
|
|
d69cb92028 | ||
|
|
e06d871aaf | ||
|
|
8a9866db54 | ||
|
|
a2e2b4e211 | ||
|
|
c5a90673b9 | ||
|
|
fbaa766f7e | ||
|
|
10008f98c3 | ||
|
|
47b10edbab | ||
|
|
6044889270 | ||
|
|
e7cac9cd0c | ||
|
|
06d0c6d98e | ||
|
|
3a21ca2f5c | ||
|
|
ad0e867b48 | ||
|
|
ae0c057b31 |
|
|
@ -10,8 +10,8 @@ orbs:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
macos:
|
macos:
|
||||||
xcode: 14.1.0 # Specify the Xcode version to use
|
xcode: 26.2.0 # Specify the Xcode version to use
|
||||||
resource_class: macos.m1.medium.gen1
|
resource_class: m4pro.medium
|
||||||
environment:
|
environment:
|
||||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||||
NPROC: 4
|
NPROC: 4
|
||||||
|
|
@ -61,10 +61,10 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
mkdir -p ~/deps
|
mkdir -p ~/deps
|
||||||
cd ~/deps
|
cd ~/deps
|
||||||
curl https://www.zlib.net/zlib-1.3.1.tar.xz | tar xz
|
curl https://www.zlib.net/zlib-1.3.2.tar.xz | tar xz
|
||||||
cd zlib-1.3.1
|
cd zlib-1.3.2
|
||||||
if [ ! -f /usr/local/lib/libz.1.3.1.dylib ]; then
|
if [ ! -f /usr/local/lib/libz.1.3.2.dylib ]; then
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
fi
|
fi
|
||||||
|
|
@ -77,7 +77,7 @@ jobs:
|
||||||
curl https://openal-soft.org/openal-releases/openal-soft-1.22.2.tar.bz2 | tar xz
|
curl https://openal-soft.org/openal-releases/openal-soft-1.22.2.tar.bz2 | tar xz
|
||||||
cd openal-soft-1.22.2
|
cd openal-soft-1.22.2
|
||||||
if [ ! -f /usr/local/lib/libopenal.1.22.2.dylib ]; then
|
if [ ! -f /usr/local/lib/libopenal.1.22.2.dylib ]; then
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DALSOFT_BACKEND_SNDIO=NO -DALSOFT_BACKEND_PORTAUDIO=NO -DALSOFT_BACKEND_WAVE=NO -DALSOFT_UTILS=NO -DALSOFT_EXAMPLES=NO -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DALSOFT_BACKEND_SNDIO=NO -DALSOFT_BACKEND_PORTAUDIO=NO -DALSOFT_BACKEND_WAVE=NO -DALSOFT_UTILS=NO -DALSOFT_EXAMPLES=NO -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
fi
|
fi
|
||||||
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
curl -L https://downloads.sourceforge.net/project/libjpeg-turbo/2.1.4/libjpeg-turbo-2.1.4.tar.gz | tar xz
|
curl -L https://downloads.sourceforge.net/project/libjpeg-turbo/2.1.4/libjpeg-turbo-2.1.4.tar.gz | tar xz
|
||||||
cd libjpeg-turbo-2.1.4
|
cd libjpeg-turbo-2.1.4
|
||||||
if [ ! -f /usr/local/lib/libturbojpeg.0.2.0.dylib ]; then
|
if [ ! -f /usr/local/lib/libturbojpeg.0.2.0.dylib ]; then
|
||||||
cmake -S. -Bbuild-x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_INSTALL_PREFIX=/usr/local
|
cmake -S. -Bbuild-x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build-x86 --config release -j$NPROC
|
cmake --build build-x86 --config release -j$NPROC
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
cd ~/deps/libjpeg-turbo-2.1.4
|
cd ~/deps/libjpeg-turbo-2.1.4
|
||||||
if [ ! -f /usr/local/lib/libturbojpeg.0.2.0.dylib ]; then
|
if [ ! -f /usr/local/lib/libturbojpeg.0.2.0.dylib ]; then
|
||||||
cmake -S. -Bbuild-arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_INSTALL_PREFIX=/usr/local
|
cmake -S. -Bbuild-arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build-arm64 --config release -j$NPROC
|
cmake --build build-arm64 --config release -j$NPROC
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ jobs:
|
||||||
curl -L https://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz | tar xz
|
curl -L https://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz | tar xz
|
||||||
cd libogg-1.3.5
|
cd libogg-1.3.5
|
||||||
if [ ! -f /usr/local/lib/libogg.0.8.5.dylib ]; then
|
if [ ! -f /usr/local/lib/libogg.0.8.5.dylib ]; then
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
fi
|
fi
|
||||||
|
|
@ -135,7 +135,7 @@ jobs:
|
||||||
curl -L https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz | tar xz
|
curl -L https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz | tar xz
|
||||||
cd libvorbis-1.3.7
|
cd libvorbis-1.3.7
|
||||||
if [ ! -f /usr/local/lib/libvorbis.0.4.9.dylib ]; then
|
if [ ! -f /usr/local/lib/libvorbis.0.4.9.dylib ]; then
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
fi
|
fi
|
||||||
|
|
@ -145,10 +145,10 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
mkdir -p ~/deps
|
mkdir -p ~/deps
|
||||||
cd ~/deps
|
cd ~/deps
|
||||||
curl -L https://download.sourceforge.net/libpng/libpng-1.6.39.tar.xz | tar xz
|
curl -L https://download.sourceforge.net/libpng/libpng-1.6.56.tar.xz | tar xz
|
||||||
cd libpng-1.6.39
|
cd libpng-1.6.56
|
||||||
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
||||||
cmake -S. -Bbuild-x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild-x86 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build-x86 --config release -j$NPROC
|
cmake --build build-x86 --config release -j$NPROC
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -157,9 +157,9 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
mkdir -p ~/deps
|
mkdir -p ~/deps
|
||||||
cd ~/deps
|
cd ~/deps
|
||||||
cd libpng-1.6.39
|
cd libpng-1.6.56
|
||||||
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
||||||
cmake -S. -Bbuild-arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild-arm64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build-arm64 --config release -j$NPROC
|
cmake --build build-arm64 --config release -j$NPROC
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -167,8 +167,8 @@ jobs:
|
||||||
name: Install libpng (Universal)
|
name: Install libpng (Universal)
|
||||||
command: |
|
command: |
|
||||||
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
if [ ! -f /usr/local/lib/libpng16.16.dylib ]; then
|
||||||
cd ~/deps/libpng-1.6.39/build-arm64
|
cd ~/deps/libpng-1.6.56/build-arm64
|
||||||
for i in libpng16.16.39.0.dylib libpng16.a png-fix-itxt pngfix pngimage pngstest pngtest pngunknown pngvalid
|
for i in libpng16.16.56.0.dylib libpng16.a png-fix-itxt pngfix pngimage pngstest pngtest pngunknown pngvalid
|
||||||
do
|
do
|
||||||
lipo -create -output $i ../build-x86/$i $i
|
lipo -create -output $i ../build-x86/$i $i
|
||||||
done
|
done
|
||||||
|
|
@ -183,7 +183,7 @@ jobs:
|
||||||
curl -L https://github.com/libsdl-org/SDL/releases/download/release-2.26.1/SDL2-2.26.1.tar.gz | tar xz
|
curl -L https://github.com/libsdl-org/SDL/releases/download/release-2.26.1/SDL2-2.26.1.tar.gz | tar xz
|
||||||
cd SDL2-2.26.1
|
cd SDL2-2.26.1
|
||||||
if [ ! -f /usr/local/lib/libSDL2-2.0.0.dylib ]; then
|
if [ ! -f /usr/local/lib/libSDL2-2.0.0.dylib ]; then
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DBUILD_SHARED_LIBS=ON -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
fi
|
fi
|
||||||
|
|
@ -194,7 +194,7 @@ jobs:
|
||||||
cd ~/deps
|
cd ~/deps
|
||||||
curl -fsSL https://github.com/libuv/libuv/archive/refs/tags/v1.44.2.tar.gz | tar xz
|
curl -fsSL https://github.com/libuv/libuv/archive/refs/tags/v1.44.2.tar.gz | tar xz
|
||||||
cd libuv-1.44.2
|
cd libuv-1.44.2
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_MACOSX_RPATH=TRUE -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
|
|
||||||
|
|
@ -213,7 +213,7 @@ jobs:
|
||||||
curl -L https://raw.githubusercontent.com/RandomityGuy/hashlink/master/libs/ssl/CMakeLists.txt > libs/ssl/CMakeLists.txt
|
curl -L https://raw.githubusercontent.com/RandomityGuy/hashlink/master/libs/ssl/CMakeLists.txt > libs/ssl/CMakeLists.txt
|
||||||
# Fix OpenAL
|
# Fix OpenAL
|
||||||
# curl -L https://github.com/nullobsi/hashlink/commit/a09491918cc4b83c2cb9fcded855fe967857385f.diff | git apply
|
# curl -L https://github.com/nullobsi/hashlink/commit/a09491918cc4b83c2cb9fcded855fe967857385f.diff | git apply
|
||||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_FIND_FRAMEWORK=LAST -DWITH_SQLITE=OFF -DBUILD_TESTING=OFF -DCMAKE_MACOSX_RPATH=TRUE -DHASHLINK_INCLUDE_DIR="~/deps/hashlink/src" -DHASHLINK_LIBRARY_DIR="/usr/local/lib/"
|
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET="10.15" -DCMAKE_FIND_FRAMEWORK=LAST -DWITH_SQLITE=OFF -DBUILD_TESTING=OFF -DCMAKE_MACOSX_RPATH=TRUE -DHASHLINK_INCLUDE_DIR="~/deps/hashlink/src" -DHASHLINK_LIBRARY_DIR="/usr/local/lib/" -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
cmake --build build --config Release -j$NPROC
|
cmake --build build --config Release -j$NPROC
|
||||||
sudo cmake --install build
|
sudo cmake --install build
|
||||||
|
|
||||||
|
|
@ -246,7 +246,7 @@ jobs:
|
||||||
- /usr/local/lib/libvorbis.0.4.9.dylib
|
- /usr/local/lib/libvorbis.0.4.9.dylib
|
||||||
- /usr/local/lib/libvorbisfile.3.3.8.dylib
|
- /usr/local/lib/libvorbisfile.3.3.8.dylib
|
||||||
- /usr/local/lib/libvorbisenc.2.0.12.dylib
|
- /usr/local/lib/libvorbisenc.2.0.12.dylib
|
||||||
- /usr/local/lib/libz.1.3.1.dylib
|
- /usr/local/lib/libz.1.3.2.dylib
|
||||||
- /usr/local/lib/datachannel.hdll
|
- /usr/local/lib/datachannel.hdll
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ jobs:
|
||||||
cp /usr/local/lib/libvorbis.0.4.9.dylib libvorbis.0.4.9.dylib
|
cp /usr/local/lib/libvorbis.0.4.9.dylib libvorbis.0.4.9.dylib
|
||||||
cp /usr/local/lib/libvorbisfile.3.3.8.dylib libvorbisfile.3.3.8.dylib
|
cp /usr/local/lib/libvorbisfile.3.3.8.dylib libvorbisfile.3.3.8.dylib
|
||||||
cp /usr/local/lib/libvorbisenc.2.0.12.dylib libvorbisenc.2.0.12.dylib
|
cp /usr/local/lib/libvorbisenc.2.0.12.dylib libvorbisenc.2.0.12.dylib
|
||||||
cp /usr/local/lib/libz.1.3.1.dylib libz.1.dylib
|
cp /usr/local/lib/libz.1.3.2.dylib libz.1.dylib
|
||||||
cp /usr/local/lib/libuv.1.dylib libuv.1.dylib
|
cp /usr/local/lib/libuv.1.dylib libuv.1.dylib
|
||||||
# These libraries have dangling RPATHs
|
# These libraries have dangling RPATHs
|
||||||
install_name_tool -delete_rpath /usr/local/lib libturbojpeg.0.dylib
|
install_name_tool -delete_rpath /usr/local/lib libturbojpeg.0.dylib
|
||||||
|
|
@ -387,7 +387,7 @@ jobs:
|
||||||
cd ~/deps
|
cd ~/deps
|
||||||
git clone https://github.com/RandomityGuy/hxDatachannel
|
git clone https://github.com/RandomityGuy/hxDatachannel
|
||||||
cd hxDatachannel/cpp
|
cd hxDatachannel/cpp
|
||||||
"/c/Program Files/CMake/bin/cmake" -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DHASHLINK_LIBRARY_DIR="~/deps/hashlink/x64/Release" -DHASHLINK_INCLUDE_DIR="../../hashlink/src"
|
"/c/Program Files/CMake/bin/cmake" -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DHASHLINK_LIBRARY_DIR="~/deps/hashlink/x64/Release" -DHASHLINK_INCLUDE_DIR="../../hashlink/src" -DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
"/c/Program Files/CMake/bin/cmake" --build build --config Release -j4
|
"/c/Program Files/CMake/bin/cmake" --build build --config Release -j4
|
||||||
mv ~/deps/hxDatachannel/cpp/build/Release/datachannel.hdll ~/deps/hashlink/x64/Release
|
mv ~/deps/hxDatachannel/cpp/build/Release/datachannel.hdll ~/deps/hashlink/x64/Release
|
||||||
mv ~/deps/hxDatachannel/cpp/build/Release/datachannel.lib ~/deps/hashlink/x64/Release
|
mv ~/deps/hxDatachannel/cpp/build/Release/datachannel.lib ~/deps/hashlink/x64/Release
|
||||||
|
|
@ -419,7 +419,7 @@ jobs:
|
||||||
haxe compile-c.hxml
|
haxe compile-c.hxml
|
||||||
cd native
|
cd native
|
||||||
HASHLINKPATH=~/deps/hashlink
|
HASHLINKPATH=~/deps/hashlink
|
||||||
MSBuild.exe -m -nologo -p:Configuration=Release -p:Platform=x64 -p:PlatformToolset=v142 -p:HASHLINK=$HASHLINKPATH marblegame.sln
|
MSBuild.exe -m -nologo -p:Configuration=Release -p:Platform=x64 -p:PlatformToolset=v142 -p:MultiProcessorCompilation=true -p:HASHLINK=$HASHLINKPATH marblegame.sln
|
||||||
- run:
|
- run:
|
||||||
name: Package app bundle
|
name: Package app bundle
|
||||||
command: |
|
command: |
|
||||||
|
|
@ -462,6 +462,8 @@ workflows:
|
||||||
filters:
|
filters:
|
||||||
tags:
|
tags:
|
||||||
only: /^\d+.\d+.\d+$/
|
only: /^\d+.\d+.\d+$/
|
||||||
|
branches:
|
||||||
|
ignore: /.*/
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
jobs:
|
jobs:
|
||||||
|
|
@ -469,3 +471,5 @@ workflows:
|
||||||
filters:
|
filters:
|
||||||
tags:
|
tags:
|
||||||
only: /^\d+.\d+.\d+$/
|
only: /^\d+.\d+.\d+$/
|
||||||
|
branches:
|
||||||
|
ignore: /.*/
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
ko_fi: randomityguy
|
||||||
46
CHANGELOG.md
|
|
@ -1,3 +1,49 @@
|
||||||
|
# 1.7.3
|
||||||
|
Hotfix time!
|
||||||
|
- Fixed chat messages being escaped a bit too much.
|
||||||
|
|
||||||
|
# 1.7.2
|
||||||
|
This update brings the following bugfixes:
|
||||||
|
- Added Import and Export Progress to Options menu to transfer game progress between devices.
|
||||||
|
- Added momentum based scrolling on touch devices for menus.
|
||||||
|
- Added TURN server support for multiplayer. Players behind strict NATs should now be able to play multiplayer without issues.
|
||||||
|
- Made the game files to be case insensitive to allow running the game on case sensitive filesystems without issues.
|
||||||
|
- Escaped all user input to prevent HTML injection in the UI.
|
||||||
|
- Fixed various race condition issues.
|
||||||
|
- Improved camera sensitivity on touch devices.
|
||||||
|
- Implemented camera centering for touch controls when free look is disabled.
|
||||||
|
- Various performance improvements and crash fixes.
|
||||||
|
- Implemented console cheat commands. DefaultMarble.attribute = value; to change marble attributes.
|
||||||
|
- Fixed a bug with the timer when playing a replay.
|
||||||
|
- Fixed a crash that could happen in multiplayer.
|
||||||
|
- Fixed not being able to load textures in certain custom levels.
|
||||||
|
- Fixed softlock when playing a user installed custom level.
|
||||||
|
- Fixed gravity changes not rewinding properly.
|
||||||
|
- Fixed skies not rendering correctly at times in the web version.
|
||||||
|
|
||||||
|
# 1.7.1
|
||||||
|
This update brings the following bugfixes:
|
||||||
|
- Fixed a crash when the marble goes out of bounds.
|
||||||
|
- Fixed the FPS limiter not limiting rendered frames per second.
|
||||||
|
- Fixed scores not being sent in certain cases.
|
||||||
|
|
||||||
|
# 1.7.0
|
||||||
|
It's the fabled Leaderboards update!
|
||||||
|
Leaderboards have been implemented for all the levels with automatic replay uploading for official levels as well as watching top replays. Additionally, segregation has been made to allow switching between rewind and non-rewind scores on the leaderboards.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Added an FPS limiter in the settings.
|
||||||
|
- Added custom friction support as well as custom marble attributes. Now levels can modify the marble's physics parameters to their liking.
|
||||||
|
- Improved level select persistence. Now your last chosen level will be displayed on quitting or finishing a level instead of last level in a category.
|
||||||
|
- Improved the Gem Hunt algorithm to match closer to PlatinumQuest's.
|
||||||
|
- Trigger detection now matches with the original game.
|
||||||
|
- Camera is now smoothened.
|
||||||
|
- Fixed camera not pointing at gems after respawn in Multiplayer.
|
||||||
|
- Fixed Superspeed powerup sometimes throwing you in the wrong direction in Multiplayer.
|
||||||
|
- Fixed the marble being wonky at times in replays.
|
||||||
|
- Fixed an interaction with Random powerup giving Time Travels.
|
||||||
|
- Fixed some collision issues with moving platforms.
|
||||||
|
|
||||||
# 1.6.1
|
# 1.6.1
|
||||||
This update fixes the following bugs:
|
This update fixes the following bugs:
|
||||||
- Fixed a crash when there are more players than spawnpoints in multiplayer.
|
- Fixed a crash when there are more players than spawnpoints in multiplayer.
|
||||||
|
|
|
||||||
27
README.md
|
|
@ -3,6 +3,7 @@ A Haxe port of Marble Blast Gold, Ultra and Platinum, name subject to change.
|
||||||
The marble physics code was taken from [OpenMBU](https://github.com/MBU-Team/OpenMBU) along with my own collision detection code, game logic was partially from scratch and taken with permission from [Marble Blast Web Port](https://github.com/Vanilagy/MarbleBlast).
|
The marble physics code was taken from [OpenMBU](https://github.com/MBU-Team/OpenMBU) along with my own collision detection code, game logic was partially from scratch and taken with permission from [Marble Blast Web Port](https://github.com/Vanilagy/MarbleBlast).
|
||||||
|
|
||||||
[](https://ko-fi.com/H2H5FRTTL)
|
[](https://ko-fi.com/H2H5FRTTL)
|
||||||
|
Support Discord: https://discord.gg/GsmTVQQAhG
|
||||||
# Play
|
# Play
|
||||||
## Web Browser
|
## Web Browser
|
||||||
The browser port supports touch controls, meaning it can be played on mobile devices.
|
The browser port supports touch controls, meaning it can be played on mobile devices.
|
||||||
|
|
@ -10,16 +11,21 @@ The browser port supports touch controls, meaning it can be played on mobile dev
|
||||||
### Marble Blast Platinum: [Play](https://marbleblast.randomityguy.me/)
|
### Marble Blast Platinum: [Play](https://marbleblast.randomityguy.me/)
|
||||||
### Marble Blast Ultra: [Play](https://marbleblastultra.randomityguy.me/)
|
### Marble Blast Ultra: [Play](https://marbleblastultra.randomityguy.me/)
|
||||||
## Windows and Mac
|
## Windows and Mac
|
||||||
### Marble Blast Gold: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.1.12)
|
### Marble Blast Gold: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.1.13)
|
||||||
### Marble Blast Platinum: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.6.1)
|
### Marble Blast Platinum: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.7.3)
|
||||||
### Marble Blast Ultra: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.1.3-mbu)
|
### Marble Blast Ultra: [Download](https://github.com/RandomityGuy/MBHaxe/releases/tag/1.2.5-mbu)
|
||||||
## Mac Instructions - Important
|
## Mac Instructions - Important
|
||||||
Put the .app file in either /Applications or ~/Applications in order to run it properly.
|
Put the .app file in either /Applications or ~/Applications in order to run it properly.
|
||||||
You will also have to bypass Gatekeeper since the .app is not signed.
|
You will also have to bypass Gatekeeper since the .app is not signed.
|
||||||
## Android
|
## Android
|
||||||
### Marble Blast Gold: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.1.12/MBHaxe-Gold.apk)
|
### Marble Blast Gold: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.1.13/MBHaxe-Gold.apk)
|
||||||
### Marble Blast Platinum: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.6.1/MBHaxe-Platinum.apk)
|
### Marble Blast Platinum: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.7.3/MBHaxe-Platinum.apk)
|
||||||
### Marble Blast Ultra: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.1.3-mbu/MBHaxe-Ultra.apk)
|
### Marble Blast Ultra: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.2.5-mbu/MBHaxe-Ultra.apk)
|
||||||
|
|
||||||
|
## Xbox (NEW!)
|
||||||
|
### Marble Blast Ultra: [Download](https://github.com/RandomityGuy/MBHaxe/releases/download/1.2.5-mbu/MBHaxe-Ultra-UWP-Xbox.msix)
|
||||||
|
Ported to Xbox via UWP by [Daniel Worley](https://github.com/worleydl).
|
||||||
|
You will need to enable Developer Mode on your Xbox in order to sideload the app. The walkthrough can be found at https://www.youtube.com/watch?v=2Ly9TIdu9uw.
|
||||||
|
|
||||||
## Additional Features
|
## Additional Features
|
||||||
- Cross Platform Multiplayer: Available in Ultra and Platinum. You can host and join multiplayer matches in any of these platforms: Windows, Mac, Web, Android.
|
- Cross Platform Multiplayer: Available in Ultra and Platinum. You can host and join multiplayer matches in any of these platforms: Windows, Mac, Web, Android.
|
||||||
|
|
@ -60,6 +66,7 @@ Requires Haxe 4.3.0 or above
|
||||||
You require the following Haxe libraries:
|
You require the following Haxe libraries:
|
||||||
- heaps: The specific version located [here](https://github.com/RandomityGuy/heaps)
|
- heaps: The specific version located [here](https://github.com/RandomityGuy/heaps)
|
||||||
- hlsdl (Obtain the haxelib version of hlsdl, then patch it with these files [here](https://github.com/RandomityGuy/hashlink/tree/master/libs/sdl)) (Hashlink/C native target)
|
- hlsdl (Obtain the haxelib version of hlsdl, then patch it with these files [here](https://github.com/RandomityGuy/hashlink/tree/master/libs/sdl)) (Hashlink/C native target)
|
||||||
|
- datachannel: obtained from [here](https://github.com/RandomityGuy/hxDatachannel)
|
||||||
- stb_ogg_sound (JS/Browser target)
|
- stb_ogg_sound (JS/Browser target)
|
||||||
- zip 1.1.0 (JS/Browser target)
|
- zip 1.1.0 (JS/Browser target)
|
||||||
|
|
||||||
|
|
@ -88,9 +95,6 @@ This will build the apk file at Export/android/app/build/outputs/apk/release/app
|
||||||
If you are on browser, please send the browser console log to me
|
If you are on browser, please send the browser console log to me
|
||||||
If you are on native, please run marbleblast-debug.bat and reproduce the crash, send the resulting stacktrace that occurs during the crash to me.
|
If you are on native, please run marbleblast-debug.bat and reproduce the crash, send the resulting stacktrace that occurs during the crash to me.
|
||||||
|
|
||||||
## Help it shows a black screen when playing a level!
|
|
||||||
Your PC does not support the game, please upgrade it, there is nothing I can do about it to fix it.
|
|
||||||
|
|
||||||
## How accurate are the marble physics?
|
## How accurate are the marble physics?
|
||||||
Very accurate with up to 1% deviation from the original physics. The deviations are due to traplaunches being slightly different and occassional internal edge collisions, and the lower delta t values for physics simulations.
|
Very accurate with up to 1% deviation from the original physics. The deviations are due to traplaunches being slightly different and occassional internal edge collisions, and the lower delta t values for physics simulations.
|
||||||
|
|
||||||
|
|
@ -99,12 +103,11 @@ In browser, you can just resize your window. You can use the browser zoom featur
|
||||||
In native version, you can just resize the window if windowed or use the resolution options in the menu or just directly modify settings.json
|
In native version, you can just resize the window if windowed or use the resolution options in the menu or just directly modify settings.json
|
||||||
|
|
||||||
## How do I change my FOV?
|
## How do I change my FOV?
|
||||||
Edit settings.json for native version, edit the MBHaxeSettings key in LocalStorage in browser.
|
There is an FOV slider in the options menu.
|
||||||
In the platinum version, there is an FOV slider.
|
|
||||||
|
|
||||||
## How do I unlock/lock FPS?
|
## How do I unlock/lock FPS?
|
||||||
You cannot unlock fps in the browser, it is forever set to vsync.
|
You cannot unlock fps in the browser, it is forever set to vsync.
|
||||||
In the native version, edit settings.json or the options menu in the platinum.
|
In the native version, use the options menu to unlock/lock fps.
|
||||||
|
|
||||||
## Hey can you please add this new feature?
|
## Hey can you please add this new feature?
|
||||||
If this new feature of yours already exists in MBG but not in this port, then I will try to add it, if I get time to do so, otherwise chances are, I won't add it since I have other things to do and would rather not waste my time on this any further. You are free to do pull requests if you have already implemented said feature.
|
If this new feature of yours already exists in MBG but not in this port, then I will try to add it, if I get time to do so, otherwise chances are, I won't add it since I have other things to do and would rather not waste my time on this any further. You are free to do pull requests if you have already implemented said feature.
|
||||||
|
|
|
||||||
BIN
data/ui/discord.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
data/ui/icon_mbg.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
data/ui/icon_mbu.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
data/ui/options/misc_d.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
data/ui/options/misc_h.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
data/ui/options/misc_i.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
data/ui/options/misc_n.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
|
|
@ -82,6 +82,12 @@ class CameraController extends Object {
|
||||||
|
|
||||||
var _ignoreCursor:Bool = false;
|
var _ignoreCursor:Bool = false;
|
||||||
|
|
||||||
|
var hasXInput:Bool = false;
|
||||||
|
var hasYInput:Bool = false;
|
||||||
|
var dt:Float;
|
||||||
|
|
||||||
|
var wasLastGamepadInput:Bool = false;
|
||||||
|
|
||||||
public function new(marble:Marble) {
|
public function new(marble:Marble) {
|
||||||
super();
|
super();
|
||||||
this.marble = marble;
|
this.marble = marble;
|
||||||
|
|
@ -166,19 +172,37 @@ class CameraController extends Object {
|
||||||
deltaposY *= len / max;
|
deltaposY *= len / max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Settings.controlsSettings.alwaysFreeLook && !Key.isDown(Settings.controlsSettings.freelook)) {
|
|
||||||
deltaposY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var factor = isTouch ? Util.lerp(1 / 25, 1 / 15,
|
var factor = isTouch ? Util.lerp(1 / 25, 1 / 15,
|
||||||
Settings.controlsSettings.cameraSensitivity) : Util.lerp(1 / 1000, 1 / 200, Settings.controlsSettings.cameraSensitivity);
|
Settings.controlsSettings.cameraSensitivity) : Util.lerp(1 / 1000, 1 / 200, Settings.controlsSettings.cameraSensitivity);
|
||||||
|
|
||||||
|
if (!Settings.controlsSettings.alwaysFreeLook && !Key.isDown(Settings.controlsSettings.freelook) && !isTouch) {
|
||||||
|
deltaposY = 0;
|
||||||
|
}
|
||||||
// CameraPitch += deltaposY * factor;
|
// CameraPitch += deltaposY * factor;
|
||||||
// CameraYaw += deltaposX * factor;
|
// CameraYaw += deltaposX * factor;
|
||||||
|
|
||||||
nextCameraPitch += deltaposY * factor;
|
nextCameraPitch += deltaposY * factor;
|
||||||
nextCameraYaw += deltaposX * factor;
|
nextCameraYaw += deltaposX * factor;
|
||||||
|
|
||||||
|
if (Math.abs(deltaposX) > 0.001)
|
||||||
|
hasXInput = true;
|
||||||
|
else
|
||||||
|
hasXInput = false;
|
||||||
|
if (Math.abs(deltaposY) > 0.001)
|
||||||
|
hasYInput = true;
|
||||||
|
else
|
||||||
|
hasYInput = false;
|
||||||
|
|
||||||
|
if (MarbleGame.instance.touchInput.cameraInput.pressed) {
|
||||||
|
hasXInput = true;
|
||||||
|
hasYInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isTouch)
|
||||||
|
wasLastGamepadInput = false;
|
||||||
|
else
|
||||||
|
wasLastGamepadInput = true;
|
||||||
|
|
||||||
// var rotX = deltaposX * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
// var rotX = deltaposX * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
||||||
// var rotY = deltaposY * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
// var rotY = deltaposY * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
||||||
// CameraYaw -= rotX;
|
// CameraYaw -= rotX;
|
||||||
|
|
@ -231,6 +255,14 @@ class CameraController extends Object {
|
||||||
overview = false;
|
overview = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function computePitchSpeedFromDelta(delta:Float) {
|
||||||
|
return Util.clamp(delta, Math.PI / 10, Math.PI / 2) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyNonlinearScale(value:Float) {
|
||||||
|
return Math.pow(Math.abs(value), 1.6) * (value >= 0 ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
function doOverviewCamera(currentTime:Float, dt:Float) {
|
function doOverviewCamera(currentTime:Float, dt:Float) {
|
||||||
var angle = Util.adjustedMod(2 * currentTime * Math.PI / 100.0, 2 * Math.PI);
|
var angle = Util.adjustedMod(2 * currentTime * Math.PI / 100.0, 2 * Math.PI);
|
||||||
var distance = overviewWidth.multiply(2.0 / 3.0);
|
var distance = overviewWidth.multiply(2.0 / 3.0);
|
||||||
|
|
@ -256,19 +288,65 @@ class CameraController extends Object {
|
||||||
function doSpectateCamera(currentTime:Float, dt:Float) {
|
function doSpectateCamera(currentTime:Float, dt:Float) {
|
||||||
var camera = level.scene.camera;
|
var camera = level.scene.camera;
|
||||||
|
|
||||||
var lerpt = Math.pow(0.5, dt / 0.032); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
var lerpt = 1 - Math.pow(0.5, dt / 0.016); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
||||||
|
|
||||||
|
var gamepadX = applyNonlinearScale(rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis), Settings.gamepadSettings.axisDeadzone));
|
||||||
|
var gamepadY = rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis), Settings.gamepadSettings.axisDeadzone);
|
||||||
|
|
||||||
|
if (gamepadX != 0.0 || gamepadY != 0.0) {
|
||||||
|
wasLastGamepadInput = true;
|
||||||
|
}
|
||||||
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
||||||
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
||||||
+ Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis);
|
+ gamepadY;
|
||||||
if (Settings.gamepadSettings.invertYAxis)
|
if (Settings.gamepadSettings.invertYAxis || Settings.controlsSettings.invertYAxis)
|
||||||
cameraPitchDelta = -cameraPitchDelta;
|
cameraPitchDelta = -cameraPitchDelta;
|
||||||
nextCameraPitch += 0.75 * 5 * cameraPitchDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0) + gamepadX;
|
||||||
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0)
|
|
||||||
+ Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis);
|
|
||||||
if (Settings.gamepadSettings.invertXAxis)
|
if (Settings.gamepadSettings.invertXAxis)
|
||||||
cameraYawDelta = -cameraYawDelta;
|
cameraYawDelta = -cameraYawDelta;
|
||||||
nextCameraYaw += 0.75 * 5 * cameraYawDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
||||||
|
if (MarbleGame.instance.paused) {
|
||||||
|
cameraYawDelta = 0;
|
||||||
|
cameraPitchDelta = 0;
|
||||||
|
}
|
||||||
|
var gamePadSensitivity = 1.0;
|
||||||
|
if (wasLastGamepadInput) {
|
||||||
|
gamePadSensitivity = Settings.gamepadSettings.cameraSensitivity; // It defaults to 0.6
|
||||||
|
}
|
||||||
|
|
||||||
|
var deltaX = 0.75 * 5 * cameraYawDelta * dt * gamePadSensitivity;
|
||||||
|
var deltaY = 0.75 * 5 * cameraPitchDelta * dt * gamePadSensitivity;
|
||||||
|
|
||||||
|
if (spectateMarbleIndex != -1) {
|
||||||
|
// Center the pitch
|
||||||
|
if (Util.isTouchDevice()) { // Do this only on touch devices
|
||||||
|
if (!Settings.controlsSettings.alwaysFreeLook
|
||||||
|
&& !Key.isDown(Settings.controlsSettings.freelook)
|
||||||
|
&& !MarbleGame.instance.touchInput.cameraInput.pressed
|
||||||
|
&& deltaY == 0.0) {
|
||||||
|
var rescaledY = deltaY;
|
||||||
|
if (rescaledY <= 0.0)
|
||||||
|
rescaledY = 0.4 - rescaledY * -0.75;
|
||||||
|
else
|
||||||
|
rescaledY = rescaledY * 1.1 + 0.4;
|
||||||
|
var movePitchDelta = (rescaledY - CameraPitch);
|
||||||
|
var movePitchSpeed = computePitchSpeedFromDelta(Math.abs(movePitchDelta)) * dt * 0.8;
|
||||||
|
if (movePitchDelta <= 0.0) {
|
||||||
|
movePitchDelta = -movePitchDelta;
|
||||||
|
if (movePitchDelta < movePitchSpeed)
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
movePitchDelta = -movePitchSpeed;
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
} else if (movePitchSpeed > movePitchDelta) {
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
}
|
||||||
|
deltaY = movePitchSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextCameraYaw += deltaX;
|
||||||
|
nextCameraPitch += deltaY;
|
||||||
|
|
||||||
var limits = spectateMarbleIndex == -1 ? 0.0001 : Math.PI / 4;
|
var limits = spectateMarbleIndex == -1 ? 0.0001 : Math.PI / 4;
|
||||||
|
|
||||||
|
|
@ -458,9 +536,10 @@ class CameraController extends Object {
|
||||||
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
||||||
firstHit = result;
|
firstHit = result;
|
||||||
firstHitDistance = rayCastOrigin.distance(result.point);
|
firstHitDistance = rayCastOrigin.distance(result.point);
|
||||||
processedShapes.push(result.object);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (firstHit != null)
|
||||||
|
processedShapes.push(firstHit.object);
|
||||||
|
|
||||||
if (firstHit != null) {
|
if (firstHit != null) {
|
||||||
if (firstHitDistance < CameraDistance) {
|
if (firstHitDistance < CameraDistance) {
|
||||||
|
|
@ -473,7 +552,7 @@ class CameraController extends Object {
|
||||||
var dist = plane.distance(camera.pos.toPoint());
|
var dist = plane.distance(camera.pos.toPoint());
|
||||||
|
|
||||||
if (dist >= closeness)
|
if (dist >= closeness)
|
||||||
break;
|
continue;
|
||||||
|
|
||||||
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
||||||
|
|
||||||
|
|
@ -493,10 +572,6 @@ class CameraController extends Object {
|
||||||
this.setPosition(camera.pos.x, camera.pos.y, camera.pos.z);
|
this.setPosition(camera.pos.x, camera.pos.y, camera.pos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyNonlinearScale(value:Float) {
|
|
||||||
return Math.pow(Math.abs(value), 3.2) * (value >= 0 ? 1 : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rescaleDeadZone(value:Float, deadZone:Float) {
|
function rescaleDeadZone(value:Float, deadZone:Float) {
|
||||||
if (deadZone >= value) {
|
if (deadZone >= value) {
|
||||||
if (-deadZone <= value)
|
if (-deadZone <= value)
|
||||||
|
|
@ -526,8 +601,8 @@ class CameraController extends Object {
|
||||||
|
|
||||||
var lerpt = 1 - Math.pow(0.5, dt / 0.016); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
var lerpt = 1 - Math.pow(0.5, dt / 0.016); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
||||||
|
|
||||||
var gamepadX = applyNonlinearScale(rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis), 0.25));
|
var gamepadX = applyNonlinearScale(rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis), Settings.gamepadSettings.axisDeadzone));
|
||||||
var gamepadY = applyNonlinearScale(rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis), 0.25));
|
var gamepadY = rescaleDeadZone(Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis), Settings.gamepadSettings.axisDeadzone);
|
||||||
|
|
||||||
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
||||||
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
||||||
|
|
@ -538,8 +613,53 @@ class CameraController extends Object {
|
||||||
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0) + gamepadX;
|
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0) + gamepadX;
|
||||||
if (Settings.gamepadSettings.invertXAxis)
|
if (Settings.gamepadSettings.invertXAxis)
|
||||||
cameraYawDelta = -cameraYawDelta;
|
cameraYawDelta = -cameraYawDelta;
|
||||||
nextCameraYaw += 0.75 * 5 * cameraYawDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
||||||
|
|
||||||
|
if (MarbleGame.instance.paused) {
|
||||||
|
cameraYawDelta = 0;
|
||||||
|
cameraPitchDelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gamePadSensitivity = 1.0;
|
||||||
|
if (wasLastGamepadInput) {
|
||||||
|
gamePadSensitivity = (1.6 - Settings.controlsSettings.cameraSensitivity); // It defaults to 0.6
|
||||||
|
}
|
||||||
|
|
||||||
|
var deltaX = 0.75 * 5 * cameraYawDelta * dt * gamePadSensitivity;
|
||||||
|
var deltaY = 0.75 * 5 * cameraPitchDelta * dt * gamePadSensitivity;
|
||||||
|
|
||||||
|
// Center the pitch
|
||||||
|
if (Util.isTouchDevice()) { // Do this only on touch devices
|
||||||
|
if (!Settings.controlsSettings.alwaysFreeLook
|
||||||
|
&& !Key.isDown(Settings.controlsSettings.freelook)
|
||||||
|
&& !MarbleGame.instance.touchInput.cameraInput.pressed
|
||||||
|
&& deltaY == 0.0) {
|
||||||
|
var rescaledY = deltaY;
|
||||||
|
if (rescaledY <= 0.0)
|
||||||
|
rescaledY = 0.4 - rescaledY * -0.75;
|
||||||
|
else
|
||||||
|
rescaledY = rescaledY * 1.1 + 0.4;
|
||||||
|
var movePitchDelta = (rescaledY - CameraPitch);
|
||||||
|
var movePitchSpeed = computePitchSpeedFromDelta(Math.abs(movePitchDelta)) * dt * 0.8;
|
||||||
|
if (movePitchDelta <= 0.0) {
|
||||||
|
movePitchDelta = -movePitchDelta;
|
||||||
|
if (movePitchDelta < movePitchSpeed)
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
movePitchDelta = -movePitchSpeed;
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
} else if (movePitchSpeed > movePitchDelta) {
|
||||||
|
movePitchSpeed = movePitchDelta;
|
||||||
|
}
|
||||||
|
deltaY = movePitchSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MarbleGame.instance.touchInput.cameraInput.pressed) {
|
||||||
|
hasXInput = false;
|
||||||
|
hasYInput = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextCameraYaw += deltaX;
|
||||||
|
nextCameraPitch += deltaY;
|
||||||
nextCameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
|
nextCameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
|
||||||
|
|
||||||
CameraYaw = Util.lerp(CameraYaw, nextCameraYaw, lerpt);
|
CameraYaw = Util.lerp(CameraYaw, nextCameraYaw, lerpt);
|
||||||
|
|
@ -632,9 +752,10 @@ class CameraController extends Object {
|
||||||
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
||||||
firstHit = result;
|
firstHit = result;
|
||||||
firstHitDistance = rayCastOrigin.distance(result.point);
|
firstHitDistance = rayCastOrigin.distance(result.point);
|
||||||
processedShapes.push(result.object);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (firstHit != null)
|
||||||
|
processedShapes.push(firstHit.object);
|
||||||
|
|
||||||
if (firstHit != null) {
|
if (firstHit != null) {
|
||||||
if (firstHitDistance < CameraDistance) {
|
if (firstHitDistance < CameraDistance) {
|
||||||
|
|
@ -647,7 +768,7 @@ class CameraController extends Object {
|
||||||
var dist = plane.distance(camera.pos.toPoint());
|
var dist = plane.distance(camera.pos.toPoint());
|
||||||
|
|
||||||
if (dist >= closeness)
|
if (dist >= closeness)
|
||||||
break;
|
continue;
|
||||||
|
|
||||||
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package src;
|
package src;
|
||||||
|
|
||||||
|
import net.Net;
|
||||||
#if !js
|
#if !js
|
||||||
import sys.FileSystem;
|
import sys.FileSystem;
|
||||||
#end
|
#end
|
||||||
|
|
@ -113,6 +114,29 @@ class Console {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function eval(cmd:String) {
|
public static function eval(cmd:String) {
|
||||||
|
var cmdLower = cmd.toLowerCase();
|
||||||
|
if (StringTools.startsWith(cmdLower, "defaultmarble")) {
|
||||||
|
// parse regex DefaultMarble.<attribName> = <value>
|
||||||
|
var regex = ~/defaultmarble\.(\w+)\s*=\s*(.+)/;
|
||||||
|
var matched = regex.match(cmdLower);
|
||||||
|
if (matched) {
|
||||||
|
var attribName = regex.matched(1);
|
||||||
|
var valueStr = regex.matched(2);
|
||||||
|
var numValue = Std.parseFloat(valueStr);
|
||||||
|
if (Math.isNaN(numValue))
|
||||||
|
numValue = 0;
|
||||||
|
if (MarbleGame.instance.world != null && !Net.isMP && MarbleGame.instance.world.marble != null) {
|
||||||
|
MarbleGame.instance.world.marble.setMarbleAttribute(attribName, numValue);
|
||||||
|
MarbleGame.instance.world.cheatsUsed = true;
|
||||||
|
log("Set DefaultMarble." + attribName + " to " + numValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("Invalid command format. Expected: DefaultMarble.<attribName> = <value>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cmdSplit = cmd.split(" ");
|
var cmdSplit = cmd.split(" ");
|
||||||
if (cmdSplit.length != 0) {
|
if (cmdSplit.length != 0) {
|
||||||
var cmdType = cmdSplit[0];
|
var cmdType = cmdSplit[0];
|
||||||
|
|
|
||||||
|
|
@ -714,17 +714,40 @@ class DifBuilder {
|
||||||
tex = spl[spl.length - 1];
|
tex = spl[spl.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// search with extension first
|
||||||
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevDir = Path.directory(Path.directory(path));
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevDir = Path.directory(prevDir);
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// remove extension from it
|
||||||
|
if (tex.lastIndexOf(".") != -1) {
|
||||||
|
tex = tex.substring(0, tex.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
|
||||||
#if (js || android)
|
#if (js || android)
|
||||||
path = StringTools.replace(path, "data/", "");
|
path = StringTools.replace(path, "data/", "");
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
// search jpg, png and bmp
|
||||||
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var prevDir = Path.directory(Path.directory(path));
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".bmp")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prevDir = Path.directory(Path.directory(path));
|
||||||
|
|
||||||
if (ResourceLoader.exists(prevDir + "/" + tex + ".jpg")) {
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".jpg")) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -732,6 +755,9 @@ class DifBuilder {
|
||||||
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".bmp")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
prevDir = Path.directory(prevDir);
|
prevDir = Path.directory(prevDir);
|
||||||
|
|
||||||
|
|
@ -741,6 +767,9 @@ class DifBuilder {
|
||||||
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".bmp")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -750,12 +779,36 @@ class DifBuilder {
|
||||||
tex = spl[spl.length - 1];
|
tex = spl[spl.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// search with extension first
|
||||||
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex)) {
|
||||||
|
return Path.directory(path) + "/" + tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevDir = Path.directory(Path.directory(path));
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex)) {
|
||||||
|
return prevDir + "/" + tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevDir = Path.directory(prevDir);
|
||||||
|
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex)) {
|
||||||
|
return prevDir + "/" + tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove extension from it
|
||||||
|
if (tex.lastIndexOf(".") != -1) {
|
||||||
|
tex = tex.substring(0, tex.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
|
||||||
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
|
||||||
return Path.directory(path) + "/" + tex + ".jpg";
|
return Path.directory(path) + "/" + tex + ".jpg";
|
||||||
}
|
}
|
||||||
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
|
||||||
return Path.directory(path) + "/" + tex + ".png";
|
return Path.directory(path) + "/" + tex + ".png";
|
||||||
}
|
}
|
||||||
|
if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".bmp")) {
|
||||||
|
return Path.directory(path) + "/" + tex + ".bmp";
|
||||||
|
}
|
||||||
|
|
||||||
var prevDir = Path.directory(Path.directory(path));
|
var prevDir = Path.directory(Path.directory(path));
|
||||||
|
|
||||||
|
|
@ -765,6 +818,9 @@ class DifBuilder {
|
||||||
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
||||||
return prevDir + "/" + tex + ".png";
|
return prevDir + "/" + tex + ".png";
|
||||||
}
|
}
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".bmp")) {
|
||||||
|
return prevDir + "/" + tex + ".bmp";
|
||||||
|
}
|
||||||
|
|
||||||
var prevDir = Path.directory(prevDir);
|
var prevDir = Path.directory(prevDir);
|
||||||
|
|
||||||
|
|
@ -774,6 +830,9 @@ class DifBuilder {
|
||||||
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
|
||||||
return prevDir + "/" + tex + ".png";
|
return prevDir + "/" + tex + ".png";
|
||||||
}
|
}
|
||||||
|
if (ResourceLoader.exists(prevDir + "/" + tex + ".bmp")) {
|
||||||
|
return prevDir + "/" + tex + ".bmp";
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,51 +158,37 @@ class InstanceManager {
|
||||||
inst.visibleTicks = inst.visibleTicks - 1;
|
inst.visibleTicks = inst.visibleTicks - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.gameObject.currentOpacity == 1)
|
var opacity = inst.gameObject.currentOpacity;
|
||||||
|
if (opacity == 1)
|
||||||
opaqueinstances.push(inst);
|
opaqueinstances.push(inst);
|
||||||
else if (inst.gameObject.currentOpacity != 0)
|
else if (opacity != 0)
|
||||||
transparentinstances.push(inst);
|
transparentinstances.push(inst);
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var dtsShader = minfo.dtsShader;
|
||||||
// Emit non culled primitives
|
// Emit non culled primitives
|
||||||
if (minfo.meshbatch != null) {
|
if (minfo.meshbatch != null) {
|
||||||
minfo.meshbatch.begin(opaqueinstances.length);
|
minfo.meshbatch.begin(opaqueinstances.length);
|
||||||
for (instance in opaqueinstances) { // Draw the opaque shit first
|
var i = 0;
|
||||||
var dtsShader = minfo.dtsShader;
|
while (i < opaqueinstances.length) {
|
||||||
if (dtsShader != null) {
|
var instance = @:privateAccess opaqueinstances.array[i++];
|
||||||
|
if (dtsShader != null)
|
||||||
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
||||||
}
|
minfo.meshbatch.worldPosition = instance.emptyObj.getAbsPos();
|
||||||
var transform = instance.emptyObj.getAbsPos();
|
|
||||||
// minfo.meshbatch.shadersChanged = true;
|
|
||||||
// minfo.meshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name);
|
|
||||||
// minfo.meshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights;
|
|
||||||
minfo.meshbatch.worldPosition = transform;
|
|
||||||
minfo.meshbatch.emitInstance();
|
minfo.meshbatch.emitInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (minfo.transparencymeshbatch != null) {
|
if (minfo.transparencymeshbatch != null) {
|
||||||
minfo.transparencymeshbatch.begin(transparentinstances.length);
|
minfo.transparencymeshbatch.begin(transparentinstances.length);
|
||||||
for (instance in transparentinstances) { // Non opaque shit
|
var i = 0;
|
||||||
var dtsShader = minfo.dtsShader;
|
while (i < transparentinstances.length) {
|
||||||
if (dtsShader != null) {
|
var instance = @:privateAccess transparentinstances.array[i++];
|
||||||
|
if (dtsShader != null)
|
||||||
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
||||||
}
|
minfo.transparencymeshbatch.worldPosition = instance.emptyObj.getAbsPos();
|
||||||
// minfo.transparencymeshbatch.material.blendMode = Alpha;
|
|
||||||
// minfo.transparencymeshbatch.material.color.a = instance.gameObject.currentOpacity;
|
|
||||||
// minfo.transparencymeshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name);
|
|
||||||
// minfo.transparencymeshbatch.shadersChanged = true;
|
|
||||||
// minfo.transparencymeshbatch.material.mainPass.enableLights = minfo.mesh.material.mainPass.enableLights;
|
|
||||||
// minfo.transparencymeshbatch.material.mainPass.depthWrite = false;
|
|
||||||
// if (dtsShader != null) {
|
|
||||||
// dtsShader.currentOpacity = instance.gameObject.currentOpacity;
|
|
||||||
// minfo.transparencymeshbatch.shadersChanged = true;
|
|
||||||
// }
|
|
||||||
var transform = instance.emptyObj.getAbsPos();
|
|
||||||
minfo.transparencymeshbatch.worldPosition = transform;
|
|
||||||
minfo.transparencymeshbatch.emitInstance();
|
minfo.transparencymeshbatch.emitInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class Leaderboards {
|
||||||
public static function getScores(mission:String, kind:LeaderboardsKind, cb:Array<LBScore>->Void) {
|
public static function getScores(mission:String, kind:LeaderboardsKind, cb:Array<LBScore>->Void) {
|
||||||
if (!StringTools.startsWith(mission, "data/"))
|
if (!StringTools.startsWith(mission, "data/"))
|
||||||
mission = "data/" + mission;
|
mission = "data/" + mission;
|
||||||
return Http.get('${host}/api/scores?mission=${StringTools.urlEncode(mission)}&game=${game}&view=${kind}&count=10', (b) -> {
|
return Http.get('${host}/api/scores?mission=${StringTools.urlEncode(mission)}&game=${game}&view=${kind}&count=5', (b) -> {
|
||||||
var s = b.toString();
|
var s = b.toString();
|
||||||
var scores:Array<LBScore> = Json.parse(s).scores;
|
var scores:Array<LBScore> = Json.parse(s).scores;
|
||||||
cb(scores);
|
cb(scores);
|
||||||
|
|
|
||||||
16
src/Main.hx
|
|
@ -137,7 +137,10 @@ class Main extends hxd.App {
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var updateDT:Float;
|
||||||
|
|
||||||
override function update(dt:Float) {
|
override function update(dt:Float) {
|
||||||
|
updateDT = dt;
|
||||||
super.update(dt);
|
super.update(dt);
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
ProfilerUI.begin();
|
ProfilerUI.begin();
|
||||||
|
|
@ -168,6 +171,19 @@ class Main extends hxd.App {
|
||||||
ProfilerUI.end();
|
ProfilerUI.end();
|
||||||
}
|
}
|
||||||
super.render(e);
|
super.render(e);
|
||||||
|
|
||||||
|
#if hl
|
||||||
|
static var dtAccumulator;
|
||||||
|
dtAccumulator += updateDT;
|
||||||
|
if (Settings.optionsSettings.fpsLimit <= 0 || Settings.optionsSettings.vsync) {
|
||||||
|
e.driver.present();
|
||||||
|
} else {
|
||||||
|
if (dtAccumulator >= 1.0 / Settings.optionsSettings.fpsLimit) {
|
||||||
|
e.driver.present();
|
||||||
|
dtAccumulator = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
static function main() {
|
static function main() {
|
||||||
|
|
|
||||||
106
src/Marble.hx
|
|
@ -260,7 +260,9 @@ class Marble extends GameObject {
|
||||||
|
|
||||||
public var contacts:Array<CollisionInfo> = [];
|
public var contacts:Array<CollisionInfo> = [];
|
||||||
public var bestContact:CollisionInfo;
|
public var bestContact:CollisionInfo;
|
||||||
public var contactEntities:Array<CollisionEntity> = [];
|
|
||||||
|
static var contactScratch:Array<CollisionEntity> = [];
|
||||||
|
static var surfaceScratch:Array<CollisionSurface> = [];
|
||||||
|
|
||||||
var queuedContacts:Array<CollisionInfo> = [];
|
var queuedContacts:Array<CollisionInfo> = [];
|
||||||
var appliedImpulses:Array<{impulse:Vector, contactImpulse:Bool}> = [];
|
var appliedImpulses:Array<{impulse:Vector, contactImpulse:Bool}> = [];
|
||||||
|
|
@ -394,6 +396,7 @@ class Marble extends GameObject {
|
||||||
this.netSmoothOffset = new Vector();
|
this.netSmoothOffset = new Vector();
|
||||||
this.netCorrected = false;
|
this.netCorrected = false;
|
||||||
this.currentUp = new Vector(0, 0, 1);
|
this.currentUp = new Vector(0, 0, 1);
|
||||||
|
this.lastContactNormal = new Vector(0, 0, 1);
|
||||||
|
|
||||||
var marbleDts = new DtsObject();
|
var marbleDts = new DtsObject();
|
||||||
var marbleShader = "";
|
var marbleShader = "";
|
||||||
|
|
@ -697,12 +700,41 @@ class Marble extends GameObject {
|
||||||
this._bounceKineticFriction = MisParser.parseNumber(attribs.get("bouncekineticfriction"));
|
this._bounceKineticFriction = MisParser.parseNumber(attribs.get("bouncekineticfriction"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setMarbleAttribute(attr:String, value:Float) {
|
||||||
|
switch (attr.toLowerCase()) {
|
||||||
|
case "maxrollvelocity":
|
||||||
|
this._maxRollVelocity = value;
|
||||||
|
case "angularacceleration":
|
||||||
|
this._angularAcceleration = value;
|
||||||
|
case "jumpimpulse":
|
||||||
|
this._jumpImpulse = value;
|
||||||
|
case "kineticfriction":
|
||||||
|
this._kineticFriction = value;
|
||||||
|
case "staticfriction":
|
||||||
|
this._staticFriction = value;
|
||||||
|
case "brakingacceleration":
|
||||||
|
this._brakingAcceleration = value;
|
||||||
|
case "gravity":
|
||||||
|
this._gravity = value;
|
||||||
|
case "airaccel":
|
||||||
|
this._airAccel = value;
|
||||||
|
case "maxdotslide":
|
||||||
|
this._maxDotSlide = value;
|
||||||
|
case "minbouncevel":
|
||||||
|
this._minBounceVel = value;
|
||||||
|
case "minbouncespeed":
|
||||||
|
this._minBounceSpeed = value;
|
||||||
|
case "mintrailvel":
|
||||||
|
this._minTrailVel = value;
|
||||||
|
case "bouncekineticfriction":
|
||||||
|
this._bounceKineticFriction = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) {
|
function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) {
|
||||||
this.contacts = queuedContacts;
|
this.contacts = queuedContacts;
|
||||||
CollisionPool.clear();
|
CollisionPool.clear();
|
||||||
var c = collisiomWorld.sphereIntersection(this.collider, timeState);
|
collisiomWorld.sphereIntersection(this.collider, timeState, this.contacts);
|
||||||
this.contactEntities = c.foundEntities;
|
|
||||||
contacts = contacts.concat(c.contacts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function queueCollision(collisionInfo:CollisionInfo) {
|
public function queueCollision(collisionInfo:CollisionInfo) {
|
||||||
|
|
@ -817,7 +849,7 @@ class Marble extends GameObject {
|
||||||
|
|
||||||
function computeMoveForces(m:Move, aControl:Vector, desiredOmega:Vector) {
|
function computeMoveForces(m:Move, aControl:Vector, desiredOmega:Vector) {
|
||||||
var currentGravityDir = this.currentUp.multiply(-1);
|
var currentGravityDir = this.currentUp.multiply(-1);
|
||||||
var R = currentGravityDir.multiply(-this._radius);
|
var R = this.currentUp.multiply(this._radius);
|
||||||
var rollVelocity = this.omega.cross(R);
|
var rollVelocity = this.omega.cross(R);
|
||||||
var axes = this.getMarbleAxis();
|
var axes = this.getMarbleAxis();
|
||||||
// if (!level.isReplayingMovement)
|
// if (!level.isReplayingMovement)
|
||||||
|
|
@ -850,15 +882,15 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
var rsq = R.lengthSq();
|
var rsq = R.lengthSq();
|
||||||
var crossP = R.cross(motionDir.multiply(desiredYVelocity).add(sideDir.multiply(desiredXVelocity))).multiply(1 / rsq);
|
var crossP = R.cross(motionDir.multiply(desiredYVelocity).add(sideDir.multiply(desiredXVelocity))).multiply(1 / rsq);
|
||||||
desiredOmega.set(crossP.x, crossP.y, crossP.z);
|
desiredOmega.load(crossP);
|
||||||
aControl.set(desiredOmega.x - this.omega.x, desiredOmega.y - this.omega.y, desiredOmega.z - this.omega.z);
|
aControl.load(desiredOmega.sub(this.omega));
|
||||||
var aScalar = aControl.length();
|
var aScalar = aControl.length();
|
||||||
if (aScalar > this._angularAcceleration) {
|
if (aScalar > this._angularAcceleration) {
|
||||||
aControl.scale(this._angularAcceleration / aScalar);
|
aControl.scale(this._angularAcceleration / aScalar);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function velocityCancel(timeState:TimeState, surfaceSlide:Bool, noBounce:Bool, stoppedPaths:Bool, pi:Array<PathedInterior>) {
|
function velocityCancel(timeState:TimeState, surfaceSlide:Bool, noBounce:Bool, stoppedPaths:Bool, pi:Array<PathedInterior>) {
|
||||||
|
|
@ -873,7 +905,7 @@ class Marble extends GameObject {
|
||||||
var sVel = this.velocity.sub(contacts[i].velocity);
|
var sVel = this.velocity.sub(contacts[i].velocity);
|
||||||
var surfaceDot = contacts[i].normal.dot(sVel);
|
var surfaceDot = contacts[i].normal.dot(sVel);
|
||||||
|
|
||||||
if ((!looped && surfaceDot < 0) || surfaceDot < -SurfaceDotThreshold) {
|
if ((!looped && surfaceDot < 0.0) || surfaceDot < -SurfaceDotThreshold) {
|
||||||
var velLen = this.velocity.length();
|
var velLen = this.velocity.length();
|
||||||
var surfaceVel = this.contacts[i].normal.multiply(surfaceDot);
|
var surfaceVel = this.contacts[i].normal.multiply(surfaceDot);
|
||||||
|
|
||||||
|
|
@ -908,7 +940,7 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
contacts[i].velocity.load(otherMarble.velocity);
|
contacts[i].velocity.load(otherMarble.velocity);
|
||||||
} else {
|
} else {
|
||||||
if (contacts[i].velocity.length() == 0 && !surfaceSlide && surfaceDot > -this._maxDotSlide * velLen) {
|
if (contacts[i].velocity.length() == 0.0 && !surfaceSlide && surfaceDot > -this._maxDotSlide * velLen) {
|
||||||
this.velocity.load(this.velocity.sub(surfaceVel));
|
this.velocity.load(this.velocity.sub(surfaceVel));
|
||||||
this.velocity.normalize();
|
this.velocity.normalize();
|
||||||
this.velocity.load(this.velocity.multiply(velLen));
|
this.velocity.load(this.velocity.multiply(velLen));
|
||||||
|
|
@ -934,7 +966,7 @@ class Marble extends GameObject {
|
||||||
vAtC.load(vAtC.sub(contacts[i].normal.multiply(contacts[i].normal.dot(sVel))));
|
vAtC.load(vAtC.sub(contacts[i].normal.multiply(contacts[i].normal.dot(sVel))));
|
||||||
|
|
||||||
var vAtCMag = vAtC.length();
|
var vAtCMag = vAtC.length();
|
||||||
if (vAtCMag != 0) {
|
if (vAtCMag != 0.0) {
|
||||||
var friction = this._bounceKineticFriction * contacts[i].friction;
|
var friction = this._bounceKineticFriction * contacts[i].friction;
|
||||||
|
|
||||||
var angVMagnitude = friction * 5 * normalVel / (2 * this._radius);
|
var angVMagnitude = friction * 5 * normalVel / (2 * this._radius);
|
||||||
|
|
@ -970,7 +1002,7 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (!done && itersIn < 1e4); // Maximum limit pls
|
} while (!done && itersIn < 1e4); // Maximum limit pls
|
||||||
if (this.velocity.lengthSq() < 625) {
|
if (this.velocity.lengthSq() < 625.0) {
|
||||||
var gotOne = false;
|
var gotOne = false;
|
||||||
var dir = new Vector(0, 0, 0);
|
var dir = new Vector(0, 0, 0);
|
||||||
for (j in 0...contacts.length) {
|
for (j in 0...contacts.length) {
|
||||||
|
|
@ -994,10 +1026,10 @@ class Marble extends GameObject {
|
||||||
soFar += (dist - outVel * timeToSeparate) / timeToSeparate / contacts[k].normal.dot(dir);
|
soFar += (dist - outVel * timeToSeparate) / timeToSeparate / contacts[k].normal.dot(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (soFar < -25)
|
if (soFar < -25.0)
|
||||||
soFar = -25;
|
soFar = -25.0;
|
||||||
if (soFar > 25)
|
if (soFar > 25.0)
|
||||||
soFar = 25;
|
soFar = 25.0;
|
||||||
this.velocity.load(this.velocity.add(dir.multiply(soFar)));
|
this.velocity.load(this.velocity.add(dir.multiply(soFar)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1066,7 +1098,7 @@ class Marble extends GameObject {
|
||||||
slipping = false;
|
slipping = false;
|
||||||
}
|
}
|
||||||
var vAtCDir = vAtC.multiply(1 / vAtCMag);
|
var vAtCDir = vAtC.multiply(1 / vAtCMag);
|
||||||
aFriction.load(bestContact.normal.multiply(-1).cross(vAtCDir.multiply(-1)).multiply(angAMagnitude));
|
aFriction.load(bestContact.normal.cross(vAtCDir).multiply(angAMagnitude));
|
||||||
AFriction.load(vAtCDir.multiply(-AMagnitude));
|
AFriction.load(vAtCDir.multiply(-AMagnitude));
|
||||||
this._slipAmount = vAtCMag - totalDeltaV;
|
this._slipAmount = vAtCMag - totalDeltaV;
|
||||||
}
|
}
|
||||||
|
|
@ -1093,16 +1125,16 @@ class Marble extends GameObject {
|
||||||
friction2 = this._kineticFriction * bestContact.friction;
|
friction2 = this._kineticFriction * bestContact.friction;
|
||||||
Aadd.load(Aadd.multiply(friction2 * bestNormalForce / aAtCMag));
|
Aadd.load(Aadd.multiply(friction2 * bestNormalForce / aAtCMag));
|
||||||
}
|
}
|
||||||
A.set(A.x + Aadd.x, A.y + Aadd.y, A.z + Aadd.z);
|
A.load(A.add(Aadd));
|
||||||
a.set(a.x + aadd.x, a.y + aadd.y, a.z + aadd.z);
|
a.load(a.add(aadd));
|
||||||
}
|
}
|
||||||
A.set(A.x + AFriction.x, A.y + AFriction.y, A.z + AFriction.z);
|
A.load(A.add(AFriction));
|
||||||
a.set(a.x + aFriction.x, a.y + aFriction.y, a.z + aFriction.z);
|
a.load(a.add(aFriction));
|
||||||
|
|
||||||
lastContactNormal = bestContact.normal;
|
lastContactNormal = bestContact.normal;
|
||||||
lastContactPosition = this.getAbsPos().getPosition();
|
lastContactPosition = this.getAbsPos().getPosition();
|
||||||
}
|
}
|
||||||
a.set(a.x + aControl.x, a.y + aControl.y, a.z + aControl.z);
|
a.load(a.add(aControl));
|
||||||
if (this.mode == Finish) {
|
if (this.mode == Finish) {
|
||||||
a.set(); // Zero it out
|
a.set(); // Zero it out
|
||||||
}
|
}
|
||||||
|
|
@ -1274,7 +1306,10 @@ class Marble extends GameObject {
|
||||||
searchbox.addSpherePos(position.x, position.y, position.z, _radius);
|
searchbox.addSpherePos(position.x, position.y, position.z, _radius);
|
||||||
searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius);
|
searchbox.addSpherePos(position.x + velocity.x * deltaT, position.y + velocity.y * deltaT, position.z + velocity.z * deltaT, _radius);
|
||||||
|
|
||||||
var foundObjs = this.collisionWorld.boundingSearch(searchbox);
|
contactScratch.resize(0);
|
||||||
|
this.collisionWorld.boundingSearch(searchbox, contactScratch);
|
||||||
|
|
||||||
|
var foundObjs = contactScratch;
|
||||||
|
|
||||||
var finalT = deltaT;
|
var finalT = deltaT;
|
||||||
var found = false;
|
var found = false;
|
||||||
|
|
@ -1317,7 +1352,7 @@ class Marble extends GameObject {
|
||||||
// var iterationFound = false;
|
// var iterationFound = false;
|
||||||
for (obj in foundObjs) {
|
for (obj in foundObjs) {
|
||||||
// Its an MP so bruh
|
// Its an MP so bruh
|
||||||
if (obj.go != null && !obj.go.isCollideable)
|
if (obj.go == this || (obj.go != null && !obj.go.isCollideable))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var isDts = obj.go is DtsObject;
|
var isDts = obj.go is DtsObject;
|
||||||
|
|
@ -1345,11 +1380,13 @@ class Marble extends GameObject {
|
||||||
Math.max(Math.max(sphereRadius.x, sphereRadius.y), sphereRadius.z) * 2);
|
Math.max(Math.max(sphereRadius.x, sphereRadius.y), sphereRadius.z) * 2);
|
||||||
|
|
||||||
var currentFinalPos = position.add(relVel.multiply(finalT)); // localpos.add(relLocalVel.multiply(finalT));
|
var currentFinalPos = position.add(relVel.multiply(finalT)); // localpos.add(relLocalVel.multiply(finalT));
|
||||||
var surfaces = @:privateAccess obj.grid != null ? @:privateAccess obj.grid.boundingSearch(boundThing) : (obj.bvh == null ? obj.octree.boundingSearch(boundThing)
|
surfaceScratch.resize(0);
|
||||||
.map(x -> cast x) : obj.bvh.boundingSearch(boundThing));
|
if (@:privateAccess obj.grid != null)
|
||||||
|
@:privateAccess obj.grid.boundingSearch(boundThing, surfaceScratch);
|
||||||
|
var surfaces = surfaceScratch;
|
||||||
|
|
||||||
for (surf in surfaces) {
|
for (surf in surfaces) {
|
||||||
var surface:CollisionSurface = cast surf;
|
var surface:CollisionSurface = surf;
|
||||||
|
|
||||||
currentFinalPos = position.add(relVel.multiply(finalT));
|
currentFinalPos = position.add(relVel.multiply(finalT));
|
||||||
|
|
||||||
|
|
@ -1371,7 +1408,7 @@ class Marble extends GameObject {
|
||||||
var surfaceNormal = new Vector(verts.nx, verts.ny,
|
var surfaceNormal = new Vector(verts.nx, verts.ny,
|
||||||
verts.nz); // surface.normals[surface.indices[i]].transformed3x3(obj.transform).normalized();
|
verts.nz); // surface.normals[surface.indices[i]].transformed3x3(obj.transform).normalized();
|
||||||
if (obj is DtsObject)
|
if (obj is DtsObject)
|
||||||
surfaceNormal.multiply(-1);
|
surfaceNormal.load(v.sub(v0).cross(v2.sub(v0)).normalized().multiply(-1));
|
||||||
var surfaceD = -surfaceNormal.dot(v0);
|
var surfaceD = -surfaceNormal.dot(v0);
|
||||||
|
|
||||||
// If we're going the wrong direction or not going to touch the plane, ignore...
|
// If we're going the wrong direction or not going to touch the plane, ignore...
|
||||||
|
|
@ -1904,7 +1941,7 @@ class Marble extends GameObject {
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
this.queuedContacts = [];
|
this.queuedContacts.resize(0);
|
||||||
|
|
||||||
newPos = this.collider.transform.getPosition(); // this.getAbsPos().getPosition().clone();
|
newPos = this.collider.transform.getPosition(); // this.getAbsPos().getPosition().clone();
|
||||||
|
|
||||||
|
|
@ -1983,7 +2020,9 @@ class Marble extends GameObject {
|
||||||
// marbleHitbox.offset(end.x, end.y, end.z);
|
// marbleHitbox.offset(end.x, end.y, end.z);
|
||||||
|
|
||||||
// spherebounds.addSpherePos(gjkCapsule.p2.x, gjkCapsule.p2.y, gjkCapsule.p2.z, gjkCapsule.radius);
|
// spherebounds.addSpherePos(gjkCapsule.p2.x, gjkCapsule.p2.y, gjkCapsule.p2.z, gjkCapsule.radius);
|
||||||
var contacts = this.collisionWorld.boundingSearch(box);
|
contactScratch.resize(0);
|
||||||
|
this.collisionWorld.boundingSearch(box, contactScratch);
|
||||||
|
var contacts = contactScratch;
|
||||||
// var contacts = marble.contactEntities;
|
// var contacts = marble.contactEntities;
|
||||||
var inside = [];
|
var inside = [];
|
||||||
|
|
||||||
|
|
@ -2036,7 +2075,9 @@ class Marble extends GameObject {
|
||||||
var checkSphereRadius = checkBounds.getMax().sub(checkBoundsCenter).length();
|
var checkSphereRadius = checkBounds.getMax().sub(checkBoundsCenter).length();
|
||||||
var checkSphere = new Bounds();
|
var checkSphere = new Bounds();
|
||||||
checkSphere.addSpherePos(checkBoundsCenter.x, checkBoundsCenter.y, checkBoundsCenter.z, checkSphereRadius);
|
checkSphere.addSpherePos(checkBoundsCenter.x, checkBoundsCenter.y, checkBoundsCenter.z, checkSphereRadius);
|
||||||
var endpadBB = this.collisionWorld.boundingSearch(checkSphere, false);
|
contactScratch.resize(0);
|
||||||
|
this.collisionWorld.boundingSearch(checkSphere, contactScratch, false);
|
||||||
|
var endpadBB = contactScratch;
|
||||||
var found = false;
|
var found = false;
|
||||||
for (collider in endpadBB) {
|
for (collider in endpadBB) {
|
||||||
if (collider.go == @:privateAccess this.level.endPad) {
|
if (collider.go == @:privateAccess this.level.endPad) {
|
||||||
|
|
@ -2390,6 +2431,8 @@ class Marble extends GameObject {
|
||||||
if (Key.isDown(Settings.controlsSettings.right)) {
|
if (Key.isDown(Settings.controlsSettings.right)) {
|
||||||
move.d.y -= 1;
|
move.d.y -= 1;
|
||||||
}
|
}
|
||||||
|
move.d.x = Util.clamp(move.d.x, -1, 1);
|
||||||
|
move.d.y = Util.clamp(move.d.y, -1, 1);
|
||||||
if (Key.isDown(Settings.controlsSettings.jump)
|
if (Key.isDown(Settings.controlsSettings.jump)
|
||||||
|| MarbleGame.instance.touchInput.jumpButton.pressed
|
|| MarbleGame.instance.touchInput.jumpButton.pressed
|
||||||
|| Gamepad.isDown(Settings.gamepadSettings.jump)) {
|
|| Gamepad.isDown(Settings.gamepadSettings.jump)) {
|
||||||
|
|
@ -2818,7 +2861,6 @@ class Marble extends GameObject {
|
||||||
this.megaMarbleUseTick = 0;
|
this.megaMarbleUseTick = 0;
|
||||||
this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.DoShockAbsorber | MarbleNetFlags.DoSuperBounce | MarbleNetFlags.PickupPowerup | MarbleNetFlags.GravityChange | MarbleNetFlags.UsePowerup;
|
this.netFlags = MarbleNetFlags.DoBlast | MarbleNetFlags.DoMega | MarbleNetFlags.DoHelicopter | MarbleNetFlags.DoShockAbsorber | MarbleNetFlags.DoSuperBounce | MarbleNetFlags.PickupPowerup | MarbleNetFlags.GravityChange | MarbleNetFlags.UsePowerup;
|
||||||
this.lastContactNormal = new Vector(0, 0, 1);
|
this.lastContactNormal = new Vector(0, 0, 1);
|
||||||
this.contactEntities = [];
|
|
||||||
this.cloak = false;
|
this.cloak = false;
|
||||||
this._firstTick = true;
|
this._firstTick = true;
|
||||||
this.lastRespawnTick = -100000;
|
this.lastRespawnTick = -100000;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class MarbleGame {
|
||||||
|
|
||||||
static var instance:MarbleGame;
|
static var instance:MarbleGame;
|
||||||
|
|
||||||
static var currentVersion = "1.7.0";
|
static var currentVersion = "1.7.3";
|
||||||
|
|
||||||
var world:MarbleWorld;
|
var world:MarbleWorld;
|
||||||
|
|
||||||
|
|
@ -88,7 +88,6 @@ class MarbleGame {
|
||||||
return; // don't pause
|
return; // don't pause
|
||||||
}
|
}
|
||||||
|
|
||||||
paused = true;
|
|
||||||
handlePauseGame();
|
handlePauseGame();
|
||||||
// Focus the shit again
|
// Focus the shit again
|
||||||
var jsCanvas = @:privateAccess Window.getInstance().canvas;
|
var jsCanvas = @:privateAccess Window.getInstance().canvas;
|
||||||
|
|
@ -260,7 +259,6 @@ class MarbleGame {
|
||||||
|| (Net.isMP && paused && !(MarbleGame.canvas.children[MarbleGame.canvas.children.length - 1] is MPExitGameDlg))) {
|
|| (Net.isMP && paused && !(MarbleGame.canvas.children[MarbleGame.canvas.children.length - 1] is MPExitGameDlg))) {
|
||||||
return; // don't pause
|
return; // don't pause
|
||||||
}
|
}
|
||||||
paused = !paused;
|
|
||||||
handlePauseGame();
|
handlePauseGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -288,13 +286,7 @@ class MarbleGame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handlePauseGame() {
|
public function showPauseUI() {
|
||||||
if (paused && world._ready) {
|
|
||||||
Console.log("Game paused");
|
|
||||||
world.setCursorLock(false);
|
|
||||||
if (Util.isTouchDevice()) {
|
|
||||||
this.touchInput.movementInput.forceRelease();
|
|
||||||
}
|
|
||||||
if (world.isMultiplayer) {
|
if (world.isMultiplayer) {
|
||||||
exitGameDlg = new MPExitGameDlg(() -> {
|
exitGameDlg = new MPExitGameDlg(() -> {
|
||||||
canvas.popDialog(exitGameDlg);
|
canvas.popDialog(exitGameDlg);
|
||||||
|
|
@ -337,8 +329,20 @@ class MarbleGame {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
canvas.pushDialog(exitGameDlg);
|
canvas.pushDialog(exitGameDlg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handlePauseGame() {
|
||||||
|
if (!paused && world._ready) {
|
||||||
|
paused = true;
|
||||||
|
Console.log("Game paused");
|
||||||
|
world.setCursorLock(false);
|
||||||
|
if (Util.isTouchDevice()) {
|
||||||
|
this.touchInput.movementInput.forceRelease();
|
||||||
|
}
|
||||||
|
showPauseUI();
|
||||||
} else {
|
} else {
|
||||||
if (world._ready) {
|
if (world._ready) {
|
||||||
|
paused = false;
|
||||||
Console.log("Game unpaused");
|
Console.log("Game unpaused");
|
||||||
if (exitGameDlg != null)
|
if (exitGameDlg != null)
|
||||||
canvas.popDialog(exitGameDlg);
|
canvas.popDialog(exitGameDlg);
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,8 @@ class MarbleWorld extends Scheduler {
|
||||||
public var rewinding:Bool = false;
|
public var rewinding:Bool = false;
|
||||||
public var rewindUsed:Bool = false;
|
public var rewindUsed:Bool = false;
|
||||||
|
|
||||||
|
public var cheatsUsed:Bool = false;
|
||||||
|
|
||||||
public var inputRecorder:InputRecorder;
|
public var inputRecorder:InputRecorder;
|
||||||
public var isReplayingMovement:Bool = false;
|
public var isReplayingMovement:Bool = false;
|
||||||
public var currentInputMoves:Array<InputRecorderFrame>;
|
public var currentInputMoves:Array<InputRecorderFrame>;
|
||||||
|
|
@ -1489,13 +1491,31 @@ class MarbleWorld extends Scheduler {
|
||||||
return packets;
|
return packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline function hasPredictionFlag(mask:Int, clientId:Int):Bool {
|
||||||
|
return (mask & (1 << clientId)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
public function applyReceivedMoves() {
|
public function applyReceivedMoves() {
|
||||||
var needsPrediction = 0;
|
var needsPrediction = 0;
|
||||||
|
|
||||||
|
inline function correctPrediction(target:Marble, packet:MarbleUpdatePacket, tick:Int, bitMask:Int, ?pending:Array<MarbleUpdatePacket>) {
|
||||||
|
target.unpackUpdate(packet);
|
||||||
|
needsPrediction |= bitMask;
|
||||||
|
if (pending != null)
|
||||||
|
pending.insert(0, packet);
|
||||||
|
if (tick >= 0)
|
||||||
|
predictions.clearStatesAfterTick(target, tick);
|
||||||
|
}
|
||||||
|
|
||||||
if (!lastMoves.ourMoveApplied) {
|
if (!lastMoves.ourMoveApplied) {
|
||||||
var ourMove = lastMoves.myMarbleUpdate;
|
var ourMove = lastMoves.myMarbleUpdate;
|
||||||
if (ourMove != null) {
|
if (ourMove != null) {
|
||||||
var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move, timeState);
|
var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move, timeState);
|
||||||
lastMoves.ourMoveApplied = true;
|
lastMoves.ourMoveApplied = true;
|
||||||
|
|
||||||
|
var hasStruct = ourMoveStruct != null;
|
||||||
|
var ourTick = hasStruct ? ourMoveStruct.timeState.ticks : -1;
|
||||||
|
|
||||||
for (client => arr in lastMoves.otherMarbleUpdates) {
|
for (client => arr in lastMoves.otherMarbleUpdates) {
|
||||||
var lastMove = null;
|
var lastMove = null;
|
||||||
while (arr.packets.length > 0) {
|
while (arr.packets.length > 0) {
|
||||||
|
|
@ -1506,68 +1526,35 @@ class MarbleWorld extends Scheduler {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastMove != null) {
|
|
||||||
// clientMarbles[Net.clientIdMap[client]].unpackUpdate(lastMove);
|
if (lastMove == null || ourMove.serverTicks != lastMove.serverTicks)
|
||||||
// needsPrediction |= 1 << client;
|
continue;
|
||||||
// arr.insert(0, lastMove);
|
|
||||||
var clientMarble = clientMarbles[Net.clientIdMap[client]];
|
var connection = Net.clientIdMap[client];
|
||||||
if (clientMarble != null) {
|
if (connection == null)
|
||||||
if (ourMove.serverTicks == lastMove.serverTicks) {
|
continue;
|
||||||
if (ourMoveStruct != null) {
|
var clientMarble = clientMarbles[connection];
|
||||||
|
if (clientMarble == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var mask = 1 << client;
|
||||||
|
if (hasStruct) {
|
||||||
var otherPred = predictions.retrieveState(clientMarble, ourMoveStruct.timeState.ticks);
|
var otherPred = predictions.retrieveState(clientMarble, ourMoveStruct.timeState.ticks);
|
||||||
if (otherPred != null) {
|
if (otherPred == null || otherPred.getError(lastMove) > 0.01) {
|
||||||
if (otherPred.getError(lastMove) > 0.01) {
|
correctPrediction(clientMarble, lastMove, ourTick, mask, arr.packets);
|
||||||
// Debug.drawSphere(@:privateAccess clientMarbles[Net.clientIdMap[client]].newPos, 0.2, 0.5);
|
|
||||||
// trace('Prediction error: ${otherPred.getError(lastMove)}');
|
|
||||||
// trace('Desync for tick ${ourMoveStruct.timeState.ticks}');
|
|
||||||
clientMarble.unpackUpdate(lastMove);
|
|
||||||
needsPrediction |= 1 << client;
|
|
||||||
arr.packets.insert(0, lastMove);
|
|
||||||
predictions.clearStatesAfterTick(clientMarbles[Net.clientIdMap[client]], ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Debug.drawSphere(@:privateAccess clientMarbles[Net.clientIdMap[client]].newPos, 0.2, 0.5);
|
correctPrediction(clientMarble, lastMove, -1, mask, arr.packets);
|
||||||
// trace('Desync for tick ${ourMoveStruct.timeState.ticks}');
|
|
||||||
clientMarble.unpackUpdate(lastMove);
|
|
||||||
needsPrediction |= 1 << client;
|
|
||||||
arr.packets.insert(0, lastMove);
|
|
||||||
predictions.clearStatesAfterTick(clientMarble, ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Debug.drawSphere(@:privateAccess clientMarbles[Net.clientIdMap[client]].newPos, 0.2, 0.5);
|
|
||||||
// trace('Desync in General');
|
|
||||||
clientMarble.unpackUpdate(lastMove);
|
|
||||||
needsPrediction |= 1 << client;
|
|
||||||
arr.packets.insert(0, lastMove);
|
|
||||||
// predictions.clearStatesAfterTick(clientMarbles[Net.clientIdMap[client]], ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// marble.unpackUpdate(ourMove);
|
|
||||||
// needsPrediction |= 1 << Net.clientId;
|
|
||||||
if (!Net.clientSpectate) {
|
if (!Net.clientSpectate) {
|
||||||
if (ourMoveStruct != null) {
|
if (hasStruct) {
|
||||||
var ourPred = predictions.retrieveState(marble, ourMoveStruct.timeState.ticks);
|
var ourPred = predictions.retrieveState(marble, ourTick);
|
||||||
if (ourPred != null) {
|
if (ourPred == null || ourPred.getError(ourMove) > 0.01) {
|
||||||
if (ourPred.getError(ourMove) > 0.01) {
|
correctPrediction(marble, ourMove, ourTick, 1 << Net.clientId);
|
||||||
// trace('Desync for tick ${ourMoveStruct.timeState.ticks}');
|
|
||||||
marble.unpackUpdate(ourMove);
|
|
||||||
needsPrediction |= 1 << Net.clientId;
|
|
||||||
predictions.clearStatesAfterTick(marble, ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// trace('Desync for tick ${ourMoveStruct.timeState.ticks}');
|
correctPrediction(marble, ourMove, -1, 1 << Net.clientId);
|
||||||
marble.unpackUpdate(ourMove);
|
|
||||||
needsPrediction |= 1 << Net.clientId;
|
|
||||||
predictions.clearStatesAfterTick(marble, ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// trace('Desync in General');
|
|
||||||
marble.unpackUpdate(ourMove);
|
|
||||||
needsPrediction |= 1 << Net.clientId;
|
|
||||||
// predictions.clearStatesAfterTick(marble, ourMoveStruct.timeState.ticks);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2524,7 +2511,7 @@ class MarbleWorld extends Scheduler {
|
||||||
} else {
|
} else {
|
||||||
nextLevelCode();
|
nextLevelCode();
|
||||||
}
|
}
|
||||||
}, mission, finishTime);
|
}, mission, finishTime, this.replay.write());
|
||||||
MarbleGame.canvas.pushDialog(egg);
|
MarbleGame.canvas.pushDialog(egg);
|
||||||
this.setCursorLock(false);
|
this.setCursorLock(false);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class ReplayFrame {
|
||||||
var t = (time - this.time) / (next.time - this.time);
|
var t = (time - this.time) / (next.time - this.time);
|
||||||
|
|
||||||
var dt = time - this.time;
|
var dt = time - this.time;
|
||||||
|
var clockDt = next.clockTime - this.clockTime;
|
||||||
|
|
||||||
var interpFrame = new ReplayFrame();
|
var interpFrame = new ReplayFrame();
|
||||||
|
|
||||||
|
|
@ -59,6 +60,7 @@ class ReplayFrame {
|
||||||
interpFrame.time = time;
|
interpFrame.time = time;
|
||||||
interpFrame.bonusTime = this.bonusTime;
|
interpFrame.bonusTime = this.bonusTime;
|
||||||
interpFrame.clockTime = this.clockTime;
|
interpFrame.clockTime = this.clockTime;
|
||||||
|
if (clockDt > 0) {
|
||||||
if (interpFrame.bonusTime != 0 && time >= 3.5) {
|
if (interpFrame.bonusTime != 0 && time >= 3.5) {
|
||||||
if (dt <= this.bonusTime) {
|
if (dt <= this.bonusTime) {
|
||||||
interpFrame.bonusTime -= dt;
|
interpFrame.bonusTime -= dt;
|
||||||
|
|
@ -73,6 +75,7 @@ class ReplayFrame {
|
||||||
interpFrame.clockTime += (this.time + dt) - 3.5;
|
interpFrame.clockTime += (this.time + dt) - 3.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Interpolate marble
|
// Interpolate marble
|
||||||
if (this.marbleStateFlags.has(InstantTeleport)) {
|
if (this.marbleStateFlags.has(InstantTeleport)) {
|
||||||
|
|
@ -291,7 +294,9 @@ class Replay {
|
||||||
|
|
||||||
public function endFrame() {
|
public function endFrame() {
|
||||||
// Do not record frames beyond par time/5 minutes to limit file size, if we aren't explicitly recording
|
// Do not record frames beyond par time/5 minutes to limit file size, if we aren't explicitly recording
|
||||||
if (!MarbleGame.instance.toRecord && currentRecordFrame.clockTime > Math.min(300, MarbleGame.instance.world.mission.qualifyTime)) {
|
if (!MarbleGame.instance.toRecord
|
||||||
|
&& currentRecordFrame != null
|
||||||
|
&& currentRecordFrame.clockTime > Math.min(300, MarbleGame.instance.world.mission.qualifyTime)) {
|
||||||
currentRecordFrame = null;
|
currentRecordFrame = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ class Settings {
|
||||||
highscoreName = "";
|
highscoreName = "";
|
||||||
}
|
}
|
||||||
userId = json.userId;
|
userId = json.userId;
|
||||||
if (userId == null) {
|
if (userId == null || userId == "") {
|
||||||
userId = Uuid.v4();
|
userId = Uuid.v4();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,14 @@ class Util {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static inline function imin(a:Int, b:Int) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function imax(a:Int, b:Int) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
public static inline function lerp(a:Float, b:Float, t:Float) {
|
public static inline function lerp(a:Float, b:Float, t:Float) {
|
||||||
return a + (b - a) * t;
|
return a + (b - a) * t;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,5 @@ class BoxCollisionEntity extends CollisionEntity implements IBVHObject {
|
||||||
return Math.POSITIVE_INFINITY;
|
return Math.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
|
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {}
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
|
|
||||||
public var octree:Octree;
|
public var octree:Octree;
|
||||||
|
|
||||||
public var bvh:BVHTree<CollisionSurface>;
|
// public var bvh:BVHTree<CollisionSurface>;
|
||||||
|
|
||||||
var grid:Grid;
|
var grid:Grid;
|
||||||
|
|
||||||
public var surfaces:Array<CollisionSurface>;
|
public var surfaces:Array<CollisionSurface>;
|
||||||
|
|
@ -67,12 +66,12 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
// Generates the bvh
|
// Generates the bvh
|
||||||
public function finalize() {
|
public function finalize() {
|
||||||
this.generateBoundingBox();
|
this.generateBoundingBox();
|
||||||
#if hl
|
// #if hl
|
||||||
this.bvh = new BVHTree();
|
// this.bvh = new BVHTree();
|
||||||
for (surface in this.surfaces) {
|
// for (surface in this.surfaces) {
|
||||||
this.bvh.add(surface);
|
// this.bvh.add(surface);
|
||||||
}
|
// }
|
||||||
#end
|
// #end
|
||||||
var bbox = new Bounds();
|
var bbox = new Bounds();
|
||||||
for (surface in this.surfaces)
|
for (surface in this.surfaces)
|
||||||
bbox.add(surface.boundingBox);
|
bbox.add(surface.boundingBox);
|
||||||
|
|
@ -90,7 +89,8 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
}
|
}
|
||||||
go = null;
|
go = null;
|
||||||
surfaces = null;
|
surfaces = null;
|
||||||
bvh = null;
|
grid = null;
|
||||||
|
// bvh = null;
|
||||||
octree = null;
|
octree = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,7 +200,9 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
|
static var surfaceSearchPool:Array<CollisionSurface> = [];
|
||||||
|
|
||||||
|
public function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
|
||||||
var position = collisionEntity.transform.getPosition();
|
var position = collisionEntity.transform.getPosition();
|
||||||
var radius = collisionEntity.radius + 0.001;
|
var radius = collisionEntity.radius + 0.001;
|
||||||
|
|
||||||
|
|
@ -215,7 +217,9 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
var invScale = invMatrix.getScale();
|
var invScale = invMatrix.getScale();
|
||||||
var sphereRadius = new Vector(radius * invScale.x, radius * invScale.y, radius * invScale.z);
|
var sphereRadius = new Vector(radius * invScale.x, radius * invScale.y, radius * invScale.z);
|
||||||
sphereBounds.addSpherePos(localPos.x, localPos.y, localPos.z, Math.max(Math.max(sphereRadius.x, sphereRadius.y), sphereRadius.z) * 1.1);
|
sphereBounds.addSpherePos(localPos.x, localPos.y, localPos.z, Math.max(Math.max(sphereRadius.x, sphereRadius.y), sphereRadius.z) * 1.1);
|
||||||
var surfaces = grid.boundingSearch(sphereBounds); // bvh == null ? octree.boundingSearch(sphereBounds).map(x -> cast x) : bvh.boundingSearch(sphereBounds);
|
surfaceSearchPool.resize(0);
|
||||||
|
grid.boundingSearch(sphereBounds, surfaceSearchPool);
|
||||||
|
var surfaces = surfaceSearchPool;
|
||||||
var invtform = invMatrix.clone();
|
var invtform = invMatrix.clone();
|
||||||
invtform.transpose();
|
invtform.transpose();
|
||||||
|
|
||||||
|
|
@ -227,8 +231,6 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
invtform.load(Matrix.I());
|
invtform.load(Matrix.I());
|
||||||
}
|
}
|
||||||
|
|
||||||
var contacts = [];
|
|
||||||
|
|
||||||
for (obj in surfaces) {
|
for (obj in surfaces) {
|
||||||
var surface:CollisionSurface = cast obj;
|
var surface:CollisionSurface = cast obj;
|
||||||
|
|
||||||
|
|
@ -301,7 +303,5 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
|
||||||
// if (surfaceBestContact != null)
|
// if (surfaceBestContact != null)
|
||||||
// contacts.push(surfaceBestContact);
|
// contacts.push(surfaceBestContact);
|
||||||
}
|
}
|
||||||
|
|
||||||
return contacts;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class CollisionHull extends CollisionEntity {
|
||||||
super(go);
|
super(go);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState):Array<CollisionInfo> {
|
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
|
||||||
var bbox = this.boundingBox;
|
var bbox = this.boundingBox;
|
||||||
var box = new Bounds();
|
var box = new Bounds();
|
||||||
var pos = collisionEntity.transform.getPosition();
|
var pos = collisionEntity.transform.getPosition();
|
||||||
|
|
@ -51,10 +51,9 @@ class CollisionHull extends CollisionEntity {
|
||||||
cinfo.friction = friction;
|
cinfo.friction = friction;
|
||||||
cinfo.force = force;
|
cinfo.force = force;
|
||||||
this.go.onMarbleContact(collisionEntity.marble, timeState, cinfo);
|
this.go.onMarbleContact(collisionEntity.marble, timeState, cinfo);
|
||||||
return [cinfo];
|
contacts.push(cinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function addSurface(surface:CollisionSurface) {
|
public override function addSurface(surface:CollisionSurface) {
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,12 @@ class CollisionWorld {
|
||||||
this.dynamicGrid.build();
|
this.dynamicGrid.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState):SphereIntersectionResult {
|
var contactList:Array<CollisionInfo> = [];
|
||||||
|
var intersectionList:Array<CollisionEntity> = [];
|
||||||
|
|
||||||
|
public function sphereIntersection(spherecollision:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
|
||||||
var position = spherecollision.transform.getPosition();
|
var position = spherecollision.transform.getPosition();
|
||||||
var radius = spherecollision.radius;
|
var radius = spherecollision.radius;
|
||||||
// var velocity = spherecollision.velocity;
|
|
||||||
// var intersections = this.octree.radiusSearch(position, searchdist);
|
|
||||||
|
|
||||||
var box = new Bounds();
|
var box = new Bounds();
|
||||||
box.addSpherePos(0, 0, 0, radius);
|
box.addSpherePos(0, 0, 0, radius);
|
||||||
|
|
@ -50,60 +51,24 @@ class CollisionWorld {
|
||||||
box.transform(rotQuat.toMatrix());
|
box.transform(rotQuat.toMatrix());
|
||||||
box.offset(position.x, position.y, position.z);
|
box.offset(position.x, position.y, position.z);
|
||||||
// box.addSpherePos(position.x + velocity.x * timeState.dt, position.y + velocity.y * timeState.dt, position.z + velocity.z * timeState.dt, radius);
|
// box.addSpherePos(position.x + velocity.x * timeState.dt, position.y + velocity.y * timeState.dt, position.z + velocity.z * timeState.dt, radius);
|
||||||
var intersections = this.grid.boundingSearch(box);
|
this.intersectionList.resize(0);
|
||||||
|
this.grid.boundingSearch(box, this.intersectionList);
|
||||||
|
dynamicGrid.boundingSearch(box, this.intersectionList);
|
||||||
|
|
||||||
// var intersections = this.rtree.search([box.xMin, box.yMax, box.zMin], [box.xSize, box.ySize, box.zSize]);
|
for (obj in this.intersectionList) {
|
||||||
|
|
||||||
var contacts = [];
|
|
||||||
var foundEntities = [];
|
|
||||||
|
|
||||||
for (obj in intersections) {
|
|
||||||
var entity:CollisionEntity = cast obj;
|
|
||||||
|
|
||||||
foundEntities.push(entity);
|
|
||||||
if (entity.go.isCollideable) {
|
|
||||||
contacts = contacts.concat(entity.sphereIntersection(spherecollision, timeState));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (marbleEntities.length > 1) {
|
|
||||||
// marbleSap.recompute();
|
|
||||||
// var sapCollisions = marbleSap.getIntersections(spherecollision);
|
|
||||||
// for (obj in sapCollisions) {
|
|
||||||
// if (obj.go.isCollideable) {
|
|
||||||
// contacts = contacts.concat(obj.sphereIntersection(spherecollision, timeState));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// contacts = contacts.concat(this.staticWorld.sphereIntersection(spherecollision, timeState));
|
|
||||||
|
|
||||||
var dynSearch = dynamicGrid.boundingSearch(box);
|
|
||||||
for (obj in dynSearch) {
|
|
||||||
if (obj != spherecollision) {
|
if (obj != spherecollision) {
|
||||||
var col = cast(obj, CollisionEntity);
|
var entity = obj;
|
||||||
if (col.boundingBox.collide(box) && col.go.isCollideable)
|
|
||||||
contacts = contacts.concat(col.sphereIntersection(spherecollision, timeState));
|
if (obj.boundingBox.collide(box) && entity.go.isCollideable) {
|
||||||
|
entity.sphereIntersection(spherecollision, timeState, contacts);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (marb in marbleEntities) {
|
public function boundingSearch(bounds:Bounds, contacts:Array<CollisionEntity>, useCache:Bool = true) {
|
||||||
// if (marb != spherecollision) {
|
this.grid.boundingSearch(bounds, contacts);
|
||||||
// if (spherecollision.go.isCollideable) {
|
dynamicGrid.boundingSearch(bounds, contacts);
|
||||||
// var isecs = marb.sphereIntersection(spherecollision, timeState);
|
|
||||||
// if (isecs.length > 0)
|
|
||||||
// foundEntities.push(marb);
|
|
||||||
// contacts = contacts.concat(isecs);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return {foundEntities: foundEntities, contacts: contacts};
|
|
||||||
}
|
|
||||||
|
|
||||||
public function boundingSearch(bounds:Bounds, useCache:Bool = true) {
|
|
||||||
var contacts = this.grid.boundingSearch(bounds).map(x -> cast(x, CollisionEntity));
|
|
||||||
contacts = contacts.concat(dynamicGrid.boundingSearch(bounds).map(x -> cast(x, CollisionEntity)));
|
|
||||||
return contacts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rayCast(rayStart:Vector, rayDirection:Vector, rayLength:Float) {
|
public function rayCast(rayStart:Vector, rayDirection:Vector, rayLength:Float) {
|
||||||
|
|
@ -116,19 +81,17 @@ class CollisionWorld {
|
||||||
+ rayDirection.x * rayLength, rayStart.y
|
+ rayDirection.x * rayLength, rayStart.y
|
||||||
+ rayDirection.y * rayLength, rayStart.z
|
+ rayDirection.y * rayLength, rayStart.z
|
||||||
+ rayDirection.z * rayLength);
|
+ rayDirection.z * rayLength);
|
||||||
var objs = this.grid.boundingSearch(bounds);
|
this.intersectionList.resize(0);
|
||||||
var dynObjs = dynamicGrid.boundingSearch(bounds);
|
|
||||||
|
this.grid.boundingSearch(bounds, this.intersectionList);
|
||||||
|
dynamicGrid.boundingSearch(bounds, this.intersectionList);
|
||||||
|
|
||||||
var results = [];
|
var results = [];
|
||||||
for (obj in objs) {
|
for (obj in this.intersectionList) {
|
||||||
var oo = cast(obj, CollisionEntity);
|
var oo = obj;
|
||||||
oo.rayCast(rayStart, rayDirection, results, rayLength);
|
oo.rayCast(rayStart, rayDirection, results, rayLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (obj in dynObjs) {
|
|
||||||
var oo = cast(obj, CollisionEntity);
|
|
||||||
oo.rayCast(rayStart, rayDirection, results, rayLength);
|
|
||||||
}
|
|
||||||
// results = results.concat(this.staticWorld.rayCast(rayStart, rayDirection));
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ class Grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
// searchbox should be in LOCAL coordinates
|
// searchbox should be in LOCAL coordinates
|
||||||
public function boundingSearch(searchbox:Bounds) {
|
public function boundingSearch(searchbox:Bounds, foundSurfaces:Array<CollisionSurface>) {
|
||||||
var queryMinX = Math.max(searchbox.xMin, bounds.xMin);
|
var queryMinX = Math.max(searchbox.xMin, bounds.xMin);
|
||||||
var queryMinY = Math.max(searchbox.yMin, bounds.yMin);
|
var queryMinY = Math.max(searchbox.yMin, bounds.yMin);
|
||||||
var queryMaxX = Math.min(searchbox.xMax, bounds.xMax);
|
var queryMaxX = Math.min(searchbox.xMax, bounds.xMax);
|
||||||
|
|
@ -94,8 +94,6 @@ class Grid {
|
||||||
if (yEnd > CELL_SIZE)
|
if (yEnd > CELL_SIZE)
|
||||||
yEnd = CELL_SIZE;
|
yEnd = CELL_SIZE;
|
||||||
|
|
||||||
var foundSurfaces = [];
|
|
||||||
|
|
||||||
searchKey++;
|
searchKey++;
|
||||||
|
|
||||||
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
||||||
|
|
@ -113,8 +111,6 @@ class Grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundSurfaces;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function elegantPair(x:Int, y:Int) {
|
function elegantPair(x:Int, y:Int) {
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,10 @@ class GridBroadphase {
|
||||||
var queryMinY = Math.max(object.boundingBox.yMin, bounds.yMin);
|
var queryMinY = Math.max(object.boundingBox.yMin, bounds.yMin);
|
||||||
var queryMaxX = Math.min(object.boundingBox.xMax, bounds.xMax);
|
var queryMaxX = Math.min(object.boundingBox.xMax, bounds.xMax);
|
||||||
var queryMaxY = Math.min(object.boundingBox.yMax, bounds.yMax);
|
var queryMaxY = Math.min(object.boundingBox.yMax, bounds.yMax);
|
||||||
var xStart = Math.floor((queryMinX - bounds.xMin) / this.cellSize.x);
|
var xStart = Util.imax(0, Math.floor((queryMinX - bounds.xMin) / this.cellSize.x));
|
||||||
var yStart = Math.floor((queryMinY - bounds.yMin) / this.cellSize.y);
|
var yStart = Util.imax(0, Math.floor((queryMinY - bounds.yMin) / this.cellSize.y));
|
||||||
var xEnd = Math.floor((queryMaxX - bounds.xMin) / this.cellSize.x);
|
var xEnd = Util.imin(CELL_SIZE - 1, Math.floor((queryMaxX - bounds.xMin) / this.cellSize.x));
|
||||||
var yEnd = Math.floor((queryMaxY - bounds.yMin) / this.cellSize.y);
|
var yEnd = Util.imin(CELL_SIZE - 1, Math.floor((queryMaxY - bounds.yMin) / this.cellSize.y));
|
||||||
var proxy = objectToProxy.get(object);
|
var proxy = objectToProxy.get(object);
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
insert(object);
|
insert(object);
|
||||||
|
|
@ -221,7 +221,7 @@ class GridBroadphase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// searchbox should be in LOCAL coordinates
|
// searchbox should be in LOCAL coordinates
|
||||||
public function boundingSearch(searchbox:Bounds) {
|
public function boundingSearch(searchbox:Bounds, foundSurfaces:Array<CollisionEntity>) {
|
||||||
var queryMinX = Math.max(searchbox.xMin, bounds.xMin);
|
var queryMinX = Math.max(searchbox.xMin, bounds.xMin);
|
||||||
var queryMinY = Math.max(searchbox.yMin, bounds.yMin);
|
var queryMinY = Math.max(searchbox.yMin, bounds.yMin);
|
||||||
var queryMaxX = Math.min(searchbox.xMax, bounds.xMax);
|
var queryMaxX = Math.min(searchbox.xMax, bounds.xMax);
|
||||||
|
|
@ -240,8 +240,6 @@ class GridBroadphase {
|
||||||
if (yEnd > CELL_SIZE)
|
if (yEnd > CELL_SIZE)
|
||||||
yEnd = CELL_SIZE;
|
yEnd = CELL_SIZE;
|
||||||
|
|
||||||
var foundSurfaces = [];
|
|
||||||
|
|
||||||
searchKey++;
|
searchKey++;
|
||||||
|
|
||||||
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
// Insert the surface references from [xStart, yStart, zStart] to [xEnd, yEnd, zEnd] into the map
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,9 @@ class SphereCollisionEntity extends CollisionEntity {
|
||||||
return Math.POSITIVE_INFINITY;
|
return Math.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState) {
|
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, timeState:TimeState, contacts:Array<CollisionInfo>) {
|
||||||
if (ignore)
|
if (ignore)
|
||||||
return [];
|
return;
|
||||||
var contacts = [];
|
|
||||||
var thispos = transform.getPosition();
|
var thispos = transform.getPosition();
|
||||||
var position = collisionEntity.transform.getPosition();
|
var position = collisionEntity.transform.getPosition();
|
||||||
var velocity = collisionEntity.velocity;
|
var velocity = collisionEntity.velocity;
|
||||||
|
|
@ -113,6 +112,5 @@ class SphereCollisionEntity extends CollisionEntity {
|
||||||
// othercontact.penetration = this.radius - (thispos.sub(othercontact.point).dot(othercontact.normal));
|
// othercontact.penetration = this.radius - (thispos.sub(othercontact.point).dot(othercontact.normal));
|
||||||
// this.marble.queueCollision(othercontact);
|
// this.marble.queueCollision(othercontact);
|
||||||
}
|
}
|
||||||
return contacts;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,19 @@ class ManifestEntry extends FileEntry {
|
||||||
if (onReady != null)
|
if (onReady != null)
|
||||||
onReady();
|
onReady();
|
||||||
} else {
|
} else {
|
||||||
js.Browser.window.fetch(file).then((res:js.html.Response) -> {
|
js.Browser.window.fetch(file)
|
||||||
|
.then((res:js.html.Response) -> {
|
||||||
|
return res.arrayBuffer();
|
||||||
|
})
|
||||||
|
.then((buf:js.lib.ArrayBuffer) -> {
|
||||||
|
loaded = true;
|
||||||
|
bytes = Bytes.ofData(buf);
|
||||||
|
if (onReady != null)
|
||||||
|
onReady();
|
||||||
|
})
|
||||||
|
.catchError((e) -> {
|
||||||
|
// Try the original file path
|
||||||
|
js.Browser.window.fetch('data/' + originalFile).then((res:js.html.Response) -> {
|
||||||
return res.arrayBuffer();
|
return res.arrayBuffer();
|
||||||
}).then((buf:js.lib.ArrayBuffer) -> {
|
}).then((buf:js.lib.ArrayBuffer) -> {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
|
|
@ -138,6 +150,7 @@ class ManifestEntry extends FileEntry {
|
||||||
if (onReady != null)
|
if (onReady != null)
|
||||||
onReady();
|
onReady();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (onReady != null)
|
if (onReady != null)
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,10 @@ class ChatCtrl extends GuiControl {
|
||||||
if (StringTools.trim(this.chatHudInput.text.text) != "") {
|
if (StringTools.trim(this.chatHudInput.text.text) != "") {
|
||||||
sendText = '<font color="#F29515">${StringTools.htmlEscape(Settings.highscoreName.substr(0, 20))}:</font> ${StringTools.htmlEscape(this.chatHudInput.text.text.substr(0, 150))}';
|
sendText = '<font color="#F29515">${StringTools.htmlEscape(Settings.highscoreName.substr(0, 20))}:</font> ${StringTools.htmlEscape(this.chatHudInput.text.text.substr(0, 150))}';
|
||||||
if (Net.isClient) {
|
if (Net.isClient) {
|
||||||
NetCommands.sendChatMessage(StringTools.htmlEscape(sendText));
|
NetCommands.sendChatMessage(sendText);
|
||||||
}
|
}
|
||||||
if (Net.isHost) {
|
if (Net.isHost) {
|
||||||
NetCommands.sendServerChatMessage(StringTools.htmlEscape(sendText));
|
NetCommands.sendServerChatMessage(sendText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.chatHudInput.text.text = "";
|
this.chatHudInput.text.text = "";
|
||||||
|
|
@ -118,7 +118,7 @@ class ChatCtrl extends GuiControl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addChatMessage(text:String) {
|
public function addChatMessage(text:String) {
|
||||||
var realText = StringTools.htmlUnescape(text);
|
var realText = text;
|
||||||
this.chats.push({
|
this.chats.push({
|
||||||
text: realText,
|
text: realText,
|
||||||
age: 10.0
|
age: 10.0
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ class EndGameGui extends GuiControl {
|
||||||
|
|
||||||
var scoreSubmitted:Bool = false;
|
var scoreSubmitted:Bool = false;
|
||||||
|
|
||||||
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, nextLevelFunc:GuiControl->Void, mission:Mission, timeState:TimeState) {
|
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, nextLevelFunc:GuiControl->Void, mission:Mission, timeState:TimeState,
|
||||||
|
replayData:haxe.io.Bytes) {
|
||||||
super();
|
super();
|
||||||
this.horizSizing = Width;
|
this.horizSizing = Width;
|
||||||
this.vertSizing = Height;
|
this.vertSizing = Height;
|
||||||
|
|
@ -70,7 +71,7 @@ class EndGameGui extends GuiControl {
|
||||||
nextLevelPreview.extent = new Vector(160, 110);
|
nextLevelPreview.extent = new Vector(160, 110);
|
||||||
nextLevel.addChild(nextLevelPreview);
|
nextLevel.addChild(nextLevelPreview);
|
||||||
|
|
||||||
mission.getNextMission().getPreviewImage(t -> {
|
mission.getNextMission()?.getPreviewImage(t -> {
|
||||||
nextLevelPreview.bmp.tile = t;
|
nextLevelPreview.bmp.tile = t;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -312,12 +313,11 @@ class EndGameGui extends GuiControl {
|
||||||
scoreData.push({name: "Matan W.", time: 5999.999});
|
scoreData.push({name: "Matan W.", time: 5999.999});
|
||||||
}
|
}
|
||||||
|
|
||||||
egFirstLine.text.text = '<p align="left"><font color="#EEC884">1. </font>${scoreData[0].name}</p>';
|
egFirstLine.text.text = '<p align="left"><font color="#EEC884">1. </font>${StringTools.htmlEscape(scoreData[0].name)}</p>';
|
||||||
egSecondLine.text.text = '<p align="left"><font color="#CDCDCD">2. </font>${scoreData[1].name}</p>';
|
egSecondLine.text.text = '<p align="left"><font color="#CDCDCD">2. </font>${StringTools.htmlEscape(scoreData[1].name)}</p>';
|
||||||
egThirdLine.text.text = '<p align="left"><font color="#C9AFA0">3. </font>${scoreData[2].name}</p>';
|
egThirdLine.text.text = '<p align="left"><font color="#C9AFA0">3. </font>${StringTools.htmlEscape(scoreData[2].name)}</p>';
|
||||||
egFourthLine.text.text = '<p align="left"><font color="#A4A4A4">4. </font>${scoreData[3].name}</p>';
|
egFourthLine.text.text = '<p align="left"><font color="#A4A4A4">4. </font>${StringTools.htmlEscape(scoreData[3].name)}</p>';
|
||||||
egFifthLine.text.text = '<p align="left"><font color="#949494">5. </font>${scoreData[4].name}</p>';
|
egFifthLine.text.text = '<p align="left"><font color="#949494">5. </font>${StringTools.htmlEscape(scoreData[4].name)}</p>';
|
||||||
|
|
||||||
var lineelems = [
|
var lineelems = [
|
||||||
egFirstLineScore,
|
egFirstLineScore,
|
||||||
egSecondLineScore,
|
egSecondLineScore,
|
||||||
|
|
@ -393,6 +393,9 @@ class EndGameGui extends GuiControl {
|
||||||
// }
|
// }
|
||||||
Settings.save();
|
Settings.save();
|
||||||
|
|
||||||
|
var rewindUsed = MarbleGame.instance.world.rewindUsed;
|
||||||
|
var cheatsUsed = MarbleGame.instance.world.cheatsUsed;
|
||||||
|
|
||||||
if (idx <= 4) {
|
if (idx <= 4) {
|
||||||
setButtonStates(false);
|
setButtonStates(false);
|
||||||
var end = new EnterNameDlg(idx, (name) -> {
|
var end = new EnterNameDlg(idx, (name) -> {
|
||||||
|
|
@ -422,41 +425,45 @@ class EndGameGui extends GuiControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cheatsUsed) { // dont submit or save if we have cheated
|
||||||
Settings.saveScore(mission.path, myScore);
|
Settings.saveScore(mission.path, myScore);
|
||||||
var lbPath = mission.path;
|
var lbPath = mission.path;
|
||||||
if (mission.isClaMission)
|
if (mission.isClaMission)
|
||||||
lbPath = 'custom/${mission.id}';
|
lbPath = 'custom/${mission.id}';
|
||||||
var replayData = MarbleGame.instance.world.replay.write();
|
Leaderboards.submitScore(lbPath, myScore.time, rewindUsed, (sendReplay, rowId) -> {
|
||||||
Leaderboards.submitScore(lbPath, myScore.time, MarbleGame.instance.world.rewindUsed, (sendReplay, rowId) -> {
|
|
||||||
if (sendReplay && !mission.isClaMission) {
|
if (sendReplay && !mission.isClaMission) {
|
||||||
Leaderboards.submitReplay(rowId, replayData);
|
Leaderboards.submitReplay(rowId, replayData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
scoreSubmitted = true;
|
scoreSubmitted = true;
|
||||||
});
|
});
|
||||||
this.addChild(end);
|
this.addChild(end);
|
||||||
} else {
|
} else {
|
||||||
// Check if we can submit LB scores
|
// Check if we can submit LB scores
|
||||||
var replayData = MarbleGame.instance.world.replay.write();
|
|
||||||
var lbPath = mission.path;
|
var lbPath = mission.path;
|
||||||
if (mission.isClaMission)
|
if (mission.isClaMission)
|
||||||
lbPath = 'custom/${mission.id}';
|
lbPath = 'custom/${mission.id}';
|
||||||
Leaderboards.getScores(lbPath, All, (scores) -> {
|
Leaderboards.getScores(lbPath, All, (scores) -> {
|
||||||
var hasMyScore = false;
|
var hasMyScore = false;
|
||||||
|
var myTopScoreLB = 0.0;
|
||||||
for (score in scores) {
|
for (score in scores) {
|
||||||
if (score.name == Settings.highscoreName) {
|
if (score.name == Settings.highscoreName) {
|
||||||
hasMyScore = true;
|
hasMyScore = true;
|
||||||
|
myTopScoreLB = score.score;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasMyScore) {
|
if (!cheatsUsed) {
|
||||||
Leaderboards.submitScore(lbPath, timeState.gameplayClock, MarbleGame.instance.world.rewindUsed, (sendReplay, rowId) -> {
|
if (!hasMyScore || (hasMyScore && myTopScoreLB > timeState.gameplayClock)) {
|
||||||
|
Leaderboards.submitScore(lbPath, timeState.gameplayClock, rewindUsed, (sendReplay, rowId) -> {
|
||||||
if (sendReplay && !mission.isClaMission) {
|
if (sendReplay && !mission.isClaMission) {
|
||||||
Leaderboards.submitReplay(rowId, replayData);
|
Leaderboards.submitReplay(rowId, replayData);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import h2d.Tile;
|
||||||
import h2d.Graphics;
|
import h2d.Graphics;
|
||||||
import src.MarbleGame;
|
import src.MarbleGame;
|
||||||
import src.Util;
|
import src.Util;
|
||||||
|
import haxe.Timer;
|
||||||
|
|
||||||
class GuiScrollCtrl extends GuiControl {
|
class GuiScrollCtrl extends GuiControl {
|
||||||
public var scrollY:Float = 0;
|
public var scrollY:Float = 0;
|
||||||
|
|
@ -40,6 +41,12 @@ class GuiScrollCtrl extends GuiControl {
|
||||||
var dirty:Bool = true;
|
var dirty:Bool = true;
|
||||||
var prevMousePos:Vector;
|
var prevMousePos:Vector;
|
||||||
|
|
||||||
|
var scrollVelocity:Float = 0;
|
||||||
|
var lastMoveStamp:Float = 0;
|
||||||
|
var momentumActive:Bool = false;
|
||||||
|
|
||||||
|
static inline var MOMENTUM_DAMPING:Float = 8;
|
||||||
|
|
||||||
var _contentYPositions:Map<h2d.Object, Float> = [];
|
var _contentYPositions:Map<h2d.Object, Float> = [];
|
||||||
|
|
||||||
var deltaY:Float = 0;
|
var deltaY:Float = 0;
|
||||||
|
|
@ -244,6 +251,9 @@ class GuiScrollCtrl extends GuiControl {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
this.updateScrollVisual();
|
this.updateScrollVisual();
|
||||||
this.prevMousePos = mouseState.position;
|
this.prevMousePos = mouseState.position;
|
||||||
|
this.scrollVelocity = 0;
|
||||||
|
this.momentumActive = false;
|
||||||
|
this.lastMoveStamp = Timer.stamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,6 +263,8 @@ class GuiScrollCtrl extends GuiControl {
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
deltaY = 0;
|
deltaY = 0;
|
||||||
this.updateScrollVisual();
|
this.updateScrollVisual();
|
||||||
|
this.momentumActive = Math.abs(scrollVelocity) > 0.01;
|
||||||
|
this.lastMoveStamp = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,15 +272,35 @@ class GuiScrollCtrl extends GuiControl {
|
||||||
if (Util.isTouchDevice()) {
|
if (Util.isTouchDevice()) {
|
||||||
super.onMouseMove(mouseState);
|
super.onMouseMove(mouseState);
|
||||||
if (this.pressed) {
|
if (this.pressed) {
|
||||||
var dy = (mouseState.position.y - this.prevMousePos.y) * scrollSpeed / this.maxScrollY;
|
var renderRect = this.getRenderRectangle();
|
||||||
|
var scrollExtentY = renderRect.extent.y;
|
||||||
|
var dy = (mouseState.position.y - this.prevMousePos.y) / ((maxScrollY * Settings.uiScale) / scrollExtentY);
|
||||||
deltaY = -dy;
|
deltaY = -dy;
|
||||||
this.scrollY -= dy;
|
this.scrollY -= dy;
|
||||||
this.prevMousePos = mouseState.position;
|
this.prevMousePos = mouseState.position;
|
||||||
|
var now = Timer.stamp();
|
||||||
|
if (lastMoveStamp > 0) {
|
||||||
|
var dt = now - lastMoveStamp;
|
||||||
|
if (dt > 0)
|
||||||
|
scrollVelocity = -dy / dt;
|
||||||
|
}
|
||||||
|
lastMoveStamp = now;
|
||||||
|
momentumActive = false;
|
||||||
this.updateScrollVisual();
|
this.updateScrollVisual();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function onMouseLeave(mouseState:MouseState) {
|
||||||
|
if (Util.isTouchDevice()) {
|
||||||
|
this.pressed = false;
|
||||||
|
this.dirty = true;
|
||||||
|
this.updateScrollVisual();
|
||||||
|
this.momentumActive = Math.abs(scrollVelocity) > 0.01;
|
||||||
|
this.lastMoveStamp = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override function update(dt:Float, mouseState:MouseState) {
|
public override function update(dt:Float, mouseState:MouseState) {
|
||||||
if (Key.isPressed(Key.MOUSE_WHEEL_DOWN) && Math.abs(mouseState.wheel) >= 1) {
|
if (Key.isPressed(Key.MOUSE_WHEEL_DOWN) && Math.abs(mouseState.wheel) >= 1) {
|
||||||
var renderRect = this.getRenderRectangle();
|
var renderRect = this.getRenderRectangle();
|
||||||
|
|
@ -285,6 +317,21 @@ class GuiScrollCtrl extends GuiControl {
|
||||||
this.updateScrollVisual();
|
this.updateScrollVisual();
|
||||||
}
|
}
|
||||||
super.update(dt, mouseState);
|
super.update(dt, mouseState);
|
||||||
|
|
||||||
|
if (!pressed && momentumActive) {
|
||||||
|
var damping = Math.exp(-MOMENTUM_DAMPING * dt);
|
||||||
|
scrollVelocity *= damping;
|
||||||
|
if (Math.abs(scrollVelocity) < 0.01) {
|
||||||
|
scrollVelocity = 0;
|
||||||
|
momentumActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var before = scrollY;
|
||||||
|
scrollY += scrollVelocity * dt;
|
||||||
|
updateScrollVisual();
|
||||||
|
if (scrollY == 0 || scrollY == before)
|
||||||
|
momentumActive = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public override function onMouseDown(mouseState:MouseState) {
|
// public override function onMouseDown(mouseState:MouseState) {
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ class JoinServerGui extends GuiImage {
|
||||||
serverInfo.text.text = '<p align="center">Select a Server</p><p align="center">or Host your own</p>';
|
serverInfo.text.text = '<p align="center">Select a Server</p><p align="center">or Host your own</p>';
|
||||||
} else {
|
} else {
|
||||||
var server = ourServerList[curSelection];
|
var server = ourServerList[curSelection];
|
||||||
serverInfo.text.text = '<p align="center">${server.name}</p><p align="center"><font face="MarkerFelt18" color="#DDDDEE">Hosted by ${server.host}</font></p><p align="left">${server.description}</p>';
|
serverInfo.text.text = '<p align="center">${StringTools.htmlEscape(server.name)}</p><p align="center"><font face="MarkerFelt18" color="#DDDDEE">Hosted by ${StringTools.htmlEscape(server.host)}</font></p><p align="left">${StringTools.htmlEscape(server.description)}</p>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverListContainer.addChild(serverList);
|
serverListContainer.addChild(serverList);
|
||||||
|
|
@ -197,7 +197,7 @@ class JoinServerGui extends GuiImage {
|
||||||
|
|
||||||
function updateServerListDisplay() {
|
function updateServerListDisplay() {
|
||||||
serverDisplays = ourServerList.map(x ->
|
serverDisplays = ourServerList.map(x ->
|
||||||
'<img src="${platformToString[x.platform]}"></img><font color="#FFFFFF">${x.name} <offset value="${400 * Settings.uiScale}">${x.players}/${x.maxPlayers}</offset></font>');
|
'<img src="${platformToString[x.platform]}"></img><font color="#FFFFFF">${StringTools.htmlEscape(x.name)} <offset value="${400 * Settings.uiScale}">${x.players}/${x.maxPlayers}</offset></font>');
|
||||||
serverList.setTexts(serverDisplays);
|
serverList.setTexts(serverDisplays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -434,10 +434,10 @@ class MPPlayMissionGui extends GuiImage {
|
||||||
if (StringTools.trim(chatInput.text.text) != "") {
|
if (StringTools.trim(chatInput.text.text) != "") {
|
||||||
var sendText = '<font color="#F29515">${StringTools.htmlEscape(Settings.highscoreName.substr(0, 20))}:</font> ${StringTools.htmlEscape(chatInput.text.text.substr(0, 100))}';
|
var sendText = '<font color="#F29515">${StringTools.htmlEscape(Settings.highscoreName.substr(0, 20))}:</font> ${StringTools.htmlEscape(chatInput.text.text.substr(0, 100))}';
|
||||||
if (Net.isClient) {
|
if (Net.isClient) {
|
||||||
NetCommands.sendChatMessage(StringTools.htmlEscape(sendText));
|
NetCommands.sendChatMessage(sendText);
|
||||||
}
|
}
|
||||||
if (Net.isHost) {
|
if (Net.isHost) {
|
||||||
NetCommands.sendServerChatMessage(StringTools.htmlEscape(sendText));
|
NetCommands.sendServerChatMessage(sendText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chatInput.text.text = "";
|
chatInput.text.text = "";
|
||||||
|
|
@ -585,11 +585,11 @@ class MPPlayMissionGui extends GuiImage {
|
||||||
currentSelection = -1;
|
currentSelection = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmDesc.text.text = '<font face="MarkerFelt32" color="#E3F3FF"><p align="center">#${currentSelection + 1}: ${currentMission.title}</p></font>'
|
pmDesc.text.text = '<font face="MarkerFelt32" color="#E3F3FF"><p align="center">#${currentSelection + 1}: ${StringTools.htmlEscape(currentMission.title)}</p></font>'
|
||||||
+ '<font face="MarkerFelt18" color="#CEE0F4">${currentMission.description}</font>';
|
+ '<font face="MarkerFelt18" color="#CEE0F4">${StringTools.htmlEscape(currentMission.description)}</font>';
|
||||||
|
|
||||||
parTime.text.text = '<font face="MarkerFelt24" color="#E3F3FF">Duration: <font color="#FFFFFF">${Util.formatTime(currentMission.qualifyTime)}</font></font><br/>'
|
parTime.text.text = '<font face="MarkerFelt24" color="#E3F3FF">Duration: <font color="#FFFFFF">${Util.formatTime(currentMission.qualifyTime)}</font></font><br/>'
|
||||||
+ '<font face="MarkerFelt24" color="#E3F3FF">Author: <font color="#FFFFFF">${currentMission.artist}</font></font>';
|
+ '<font face="MarkerFelt24" color="#E3F3FF">Author: <font color="#FFFFFF">${StringTools.htmlEscape(currentMission.artist)}</font></font>';
|
||||||
|
|
||||||
// pmPreview.bmp.tile = tmpprevtile;
|
// pmPreview.bmp.tile = tmpprevtile;
|
||||||
#if js
|
#if js
|
||||||
|
|
@ -718,7 +718,7 @@ class MPPlayMissionGui extends GuiImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerListCompiled = playerListArr.map(player ->
|
var playerListCompiled = playerListArr.map(player ->
|
||||||
'<img src="${platformToString(player.platform)}"></img><font color="#FFFFFF">${player.name}<offset value="${220 * Settings.uiScale}">${player.ready ? "Ready" : ""}</offset></font>');
|
'<img src="${platformToString(player.platform)}"></img><font color="#FFFFFF">${StringTools.htmlEscape(player.name)}<offset value="${220 * Settings.uiScale}">${player.ready ? "Ready" : ""}</offset></font>');
|
||||||
playerListCtrl.setTexts(playerListCompiled);
|
playerListCtrl.setTexts(playerListCompiled);
|
||||||
|
|
||||||
// if (!showingCustoms)
|
// if (!showingCustoms)
|
||||||
|
|
@ -728,7 +728,7 @@ class MPPlayMissionGui extends GuiImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function addChatMessage(s:String) {
|
public static function addChatMessage(s:String) {
|
||||||
var realText = StringTools.htmlUnescape(s);
|
var realText = s;
|
||||||
allChats.push(realText);
|
allChats.push(realText);
|
||||||
if (allChats.length > 100) {
|
if (allChats.length > 100) {
|
||||||
allChats = allChats.slice(allChats.length - 100);
|
allChats = allChats.slice(allChats.length - 100);
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@ class MainMenuGui extends GuiImage {
|
||||||
return [normal, hover, pressed];
|
return [normal, hover, pressed];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadStaticButtonImages(path:String) {
|
||||||
|
var normal = ResourceLoader.getResource('${path}.png', ResourceLoader.getImage, this.imageResources).toTile();
|
||||||
|
var hover = ResourceLoader.getResource('${path}.png', ResourceLoader.getImage, this.imageResources).toTile();
|
||||||
|
var pressed = ResourceLoader.getResource('${path}.png', ResourceLoader.getImage, this.imageResources).toTile();
|
||||||
|
return [normal, hover, pressed];
|
||||||
|
}
|
||||||
|
|
||||||
var siteButton = new GuiButton(loadButtonImages('data/ui/menu/site'));
|
var siteButton = new GuiButton(loadButtonImages('data/ui/menu/site'));
|
||||||
siteButton.horizSizing = Right;
|
siteButton.horizSizing = Right;
|
||||||
siteButton.vertSizing = Top;
|
siteButton.vertSizing = Top;
|
||||||
|
|
@ -232,6 +239,38 @@ class MainMenuGui extends GuiImage {
|
||||||
}
|
}
|
||||||
this.addChild(github);
|
this.addChild(github);
|
||||||
|
|
||||||
|
#if js
|
||||||
|
var mbg = new GuiButton(loadStaticButtonImages("data/ui/icon_mbg"));
|
||||||
|
mbg.horizSizing = Right;
|
||||||
|
mbg.vertSizing = Top;
|
||||||
|
mbg.position = new Vector(0, 380);
|
||||||
|
mbg.extent = new Vector(76, 76);
|
||||||
|
mbg.pressedAction = (sender) -> {
|
||||||
|
js.Browser.window.open("https://marbleblastgold.randomityguy.me");
|
||||||
|
}
|
||||||
|
this.addChild(mbg);
|
||||||
|
|
||||||
|
var mbu = new GuiButton(loadStaticButtonImages("data/ui/icon_mbu"));
|
||||||
|
mbu.horizSizing = Right;
|
||||||
|
mbu.vertSizing = Top;
|
||||||
|
mbu.position = new Vector(76, 380);
|
||||||
|
mbu.extent = new Vector(76, 76);
|
||||||
|
mbu.pressedAction = (sender) -> {
|
||||||
|
js.Browser.window.open("https://marbleblastultra.randomityguy.me");
|
||||||
|
}
|
||||||
|
this.addChild(mbu);
|
||||||
|
|
||||||
|
var discord = new GuiButton(loadStaticButtonImages("data/ui/discord"));
|
||||||
|
discord.horizSizing = Right;
|
||||||
|
discord.vertSizing = Top;
|
||||||
|
discord.position = new Vector(0, 320);
|
||||||
|
discord.extent = new Vector(152, 60);
|
||||||
|
discord.pressedAction = (sender) -> {
|
||||||
|
js.Browser.window.open("https://discord.gg/q4JdnRbVhF");
|
||||||
|
}
|
||||||
|
this.addChild(discord);
|
||||||
|
#end
|
||||||
|
|
||||||
#if js
|
#if js
|
||||||
var urlParams = new js.html.URLSearchParams(js.Browser.window.location.search);
|
var urlParams = new js.html.URLSearchParams(js.Browser.window.location.search);
|
||||||
var playParam = urlParams.get("app");
|
var playParam = urlParams.get("app");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package gui;
|
package gui;
|
||||||
|
|
||||||
|
import haxe.DynamicAccess;
|
||||||
import hxd.BitmapData;
|
import hxd.BitmapData;
|
||||||
import h2d.filter.DropShadow;
|
import h2d.filter.DropShadow;
|
||||||
import h2d.Text;
|
import h2d.Text;
|
||||||
|
|
@ -70,10 +71,10 @@ class OptionsDlg extends GuiImage {
|
||||||
hotkeysBtn.extent = new Vector(134, 65);
|
hotkeysBtn.extent = new Vector(134, 65);
|
||||||
window.addChild(hotkeysBtn);
|
window.addChild(hotkeysBtn);
|
||||||
|
|
||||||
var onlineBtn = new GuiImage(ResourceLoader.getResource("data/ui/options/online_i.png", ResourceLoader.getImage, this.imageResources).toTile());
|
var miscBtn = new GuiButton(loadButtonImages('data/ui/options/misc'));
|
||||||
onlineBtn.position = new Vector(548, 19);
|
miscBtn.position = new Vector(548, 19);
|
||||||
onlineBtn.extent = new Vector(134, 65);
|
miscBtn.extent = new Vector(134, 65);
|
||||||
window.addChild(onlineBtn);
|
window.addChild(miscBtn);
|
||||||
|
|
||||||
var generalPanel:GuiScrollCtrl = null;
|
var generalPanel:GuiScrollCtrl = null;
|
||||||
|
|
||||||
|
|
@ -114,6 +115,10 @@ class OptionsDlg extends GuiImage {
|
||||||
hotkeysPanel.position = new Vector(30, 88);
|
hotkeysPanel.position = new Vector(30, 88);
|
||||||
hotkeysPanel.extent = new Vector(726, 394);
|
hotkeysPanel.extent = new Vector(726, 394);
|
||||||
|
|
||||||
|
var miscPanel = new GuiControl();
|
||||||
|
miscPanel.position = new Vector(30, 88);
|
||||||
|
miscPanel.extent = new Vector(726, 394);
|
||||||
|
|
||||||
var markerFelt32fontdata = ResourceLoader.getFileEntry("data/font/MarkerFelt.fnt");
|
var markerFelt32fontdata = ResourceLoader.getFileEntry("data/font/MarkerFelt.fnt");
|
||||||
var markerFelt32b = new BitmapFont(markerFelt32fontdata.entry);
|
var markerFelt32b = new BitmapFont(markerFelt32fontdata.entry);
|
||||||
@:privateAccess markerFelt32b.loader = ResourceLoader.loader;
|
@:privateAccess markerFelt32b.loader = ResourceLoader.loader;
|
||||||
|
|
@ -470,6 +475,31 @@ class OptionsDlg extends GuiImage {
|
||||||
parent.addChild(remapBtn);
|
parent.addChild(remapBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeButton(text:String, yPos:Int, buttonText:String, pressedAction:() -> Void, parent:GuiControl, right:Bool = false) {
|
||||||
|
var textObj = new GuiText(markerFelt32);
|
||||||
|
textObj.position = new Vector(right ? 368 : 5, yPos);
|
||||||
|
textObj.extent = new Vector(212, 14);
|
||||||
|
textObj.text.text = text;
|
||||||
|
textObj.text.textColor = 0xFFFFFF;
|
||||||
|
textObj.text.dropShadow = {
|
||||||
|
dx: 1 * Settings.uiScale,
|
||||||
|
dy: 1 * Settings.uiScale,
|
||||||
|
alpha: 0.5,
|
||||||
|
color: 0
|
||||||
|
};
|
||||||
|
parent.addChild(textObj);
|
||||||
|
|
||||||
|
var btn = new GuiButtonText(loadButtonImages("data/ui/options/bind"), markerFelt24);
|
||||||
|
btn.position = new Vector(right ? 363 + 203 : 203, yPos - 3);
|
||||||
|
btn.txtCtrl.text.text = buttonText;
|
||||||
|
btn.setExtent(new Vector(152, 49));
|
||||||
|
btn.pressedAction = (sender) -> {
|
||||||
|
pressedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.addChild(btn);
|
||||||
|
}
|
||||||
|
|
||||||
if (Util.isTouchDevice()) {
|
if (Util.isTouchDevice()) {
|
||||||
var textObj = new GuiText(markerFelt32);
|
var textObj = new GuiText(markerFelt32);
|
||||||
textObj.position = new Vector(5, 38);
|
textObj.position = new Vector(5, 38);
|
||||||
|
|
@ -540,10 +570,85 @@ class OptionsDlg extends GuiImage {
|
||||||
hotkeysPanel, true);
|
hotkeysPanel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MISC PANEL
|
||||||
|
makeButton("Import Progress:", 38, "Import", () -> {
|
||||||
|
hxd.File.browse((sel) -> {
|
||||||
|
sel.load((data) -> {
|
||||||
|
try {
|
||||||
|
// convert to string
|
||||||
|
var jsonStr = data.toString();
|
||||||
|
// parse JSON
|
||||||
|
var json = haxe.Json.parse(jsonStr);
|
||||||
|
|
||||||
|
var highScoreData:DynamicAccess<Array<Score>> = json.highScores;
|
||||||
|
for (key => value in highScoreData) {
|
||||||
|
Settings.highScores.set(key, value);
|
||||||
|
}
|
||||||
|
var easterEggData:DynamicAccess<Float> = json.easterEggs;
|
||||||
|
if (easterEggData != null) {
|
||||||
|
for (key => value in easterEggData) {
|
||||||
|
Settings.easterEggs.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Progress data imported successfully!"));
|
||||||
|
Settings.save();
|
||||||
|
} catch (e) {
|
||||||
|
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Failed to import progress data: " + e.message));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
title: "Select a progress file to import",
|
||||||
|
fileTypes: [
|
||||||
|
{name: "JSON files", extensions: ["json"]},
|
||||||
|
{name: "All files", extensions: ["*"]}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}, miscPanel);
|
||||||
|
makeButton("Export Progress:", 38, "Export", () -> {
|
||||||
|
#if sys
|
||||||
|
#if MACOS_BUNDLE
|
||||||
|
// open the finder to that folder
|
||||||
|
Sys.command('open "${Settings.settingsDir}"');
|
||||||
|
#else
|
||||||
|
// Just open the folder in the explorer.exe
|
||||||
|
Sys.command('explorer.exe "${Settings.settingsDir}"');
|
||||||
|
#end
|
||||||
|
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("The settings.json file contains your progress data. You can copy it to another device or share it with others."));
|
||||||
|
#end
|
||||||
|
#if js
|
||||||
|
// Serialize Settings to JSON
|
||||||
|
var localStorage = js.Browser.getLocalStorage();
|
||||||
|
if (localStorage != null) {
|
||||||
|
var settingsData = localStorage.getItem("MBHaxeSettings");
|
||||||
|
if (settingsData != null) {
|
||||||
|
// Download this
|
||||||
|
var replayBytes = settingsData;
|
||||||
|
var blob = new js.html.Blob([haxe.io.Bytes.ofString(replayBytes).getData()], {
|
||||||
|
type: 'application/octet-stream'
|
||||||
|
});
|
||||||
|
var url = js.html.URL.createObjectURL(blob);
|
||||||
|
var fname = 'settings.json';
|
||||||
|
var element = js.Browser.document.createElement('a');
|
||||||
|
element.setAttribute('href', url);
|
||||||
|
element.setAttribute('download', fname);
|
||||||
|
|
||||||
|
element.style.display = 'none';
|
||||||
|
js.Browser.document.body.appendChild(element);
|
||||||
|
|
||||||
|
element.click();
|
||||||
|
|
||||||
|
js.Browser.document.body.removeChild(element);
|
||||||
|
js.html.URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}, miscPanel, true);
|
||||||
|
|
||||||
generalBtn.pressedAction = (e) -> {
|
generalBtn.pressedAction = (e) -> {
|
||||||
if (currentTab != "general") {
|
if (currentTab != "general") {
|
||||||
currentTab = "general";
|
currentTab = "general";
|
||||||
hotkeysPanel.parent.removeChild(hotkeysPanel);
|
hotkeysPanel.parent?.removeChild(hotkeysPanel);
|
||||||
|
miscPanel.parent?.removeChild(miscPanel);
|
||||||
generalPanel.scrollY = 0;
|
generalPanel.scrollY = 0;
|
||||||
window.addChild(generalPanel);
|
window.addChild(generalPanel);
|
||||||
MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh
|
MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh
|
||||||
|
|
@ -553,12 +658,23 @@ class OptionsDlg extends GuiImage {
|
||||||
hotkeysBtn.pressedAction = (e) -> {
|
hotkeysBtn.pressedAction = (e) -> {
|
||||||
if (currentTab != "hotkeys") {
|
if (currentTab != "hotkeys") {
|
||||||
currentTab = "hotkeys";
|
currentTab = "hotkeys";
|
||||||
generalPanel.parent.removeChild(generalPanel);
|
generalPanel.parent?.removeChild(generalPanel);
|
||||||
|
miscPanel.parent?.removeChild(miscPanel);
|
||||||
window.addChild(hotkeysPanel);
|
window.addChild(hotkeysPanel);
|
||||||
MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh
|
MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
miscBtn.pressedAction = (e) -> {
|
||||||
|
if (currentTab != "misc") {
|
||||||
|
currentTab = "misc";
|
||||||
|
generalPanel.parent?.removeChild(generalPanel);
|
||||||
|
hotkeysPanel.parent?.removeChild(hotkeysPanel);
|
||||||
|
window.addChild(miscPanel);
|
||||||
|
MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// // Touch Controls buttons???
|
// // Touch Controls buttons???
|
||||||
// if (Util.isTouchDevice()) {
|
// if (Util.isTouchDevice()) {
|
||||||
// var touchControlsTxt = new GuiText(domcasual24);
|
// var touchControlsTxt = new GuiText(domcasual24);
|
||||||
|
|
|
||||||
|
|
@ -566,17 +566,17 @@ class PlayGui {
|
||||||
|
|
||||||
var fpsMeterCtrl = new GuiImage(ResourceLoader.getResource("data/ui/game/transparency-fps.png", ResourceLoader.getImage, this.imageResources)
|
var fpsMeterCtrl = new GuiImage(ResourceLoader.getResource("data/ui/game/transparency-fps.png", ResourceLoader.getImage, this.imageResources)
|
||||||
.toTile());
|
.toTile());
|
||||||
fpsMeterCtrl.position = new Vector(544, 448);
|
fpsMeterCtrl.position = new Vector(534, 448);
|
||||||
fpsMeterCtrl.horizSizing = Left;
|
fpsMeterCtrl.horizSizing = Left;
|
||||||
fpsMeterCtrl.vertSizing = Top;
|
fpsMeterCtrl.vertSizing = Top;
|
||||||
fpsMeterCtrl.extent = new Vector(96, 32);
|
fpsMeterCtrl.extent = new Vector(106, 32);
|
||||||
|
|
||||||
fpsMeter = new GuiText(bfont);
|
fpsMeter = new GuiText(bfont);
|
||||||
fpsMeter.horizSizing = Width;
|
fpsMeter.horizSizing = Width;
|
||||||
fpsMeter.vertSizing = Height;
|
fpsMeter.vertSizing = Height;
|
||||||
fpsMeter.position = new Vector(10, 3);
|
fpsMeter.position = new Vector(10, 3);
|
||||||
fpsMeter.text.textColor = 0;
|
fpsMeter.text.textColor = 0;
|
||||||
fpsMeter.extent = new Vector(96, 32);
|
fpsMeter.extent = new Vector(106, 32);
|
||||||
fpsMeterCtrl.addChild(fpsMeter);
|
fpsMeterCtrl.addChild(fpsMeter);
|
||||||
|
|
||||||
playGuiCtrl.addChild(fpsMeterCtrl);
|
playGuiCtrl.addChild(fpsMeterCtrl);
|
||||||
|
|
@ -738,7 +738,7 @@ class PlayGui {
|
||||||
} else {
|
} else {
|
||||||
isSpectating = Net.clientIdMap[item.id].spectator;
|
isSpectating = Net.clientIdMap[item.id].spectator;
|
||||||
}
|
}
|
||||||
pl.push('<font color="${color}">${i + 1}. ${isSpectating ? "[S] " : ""}${Util.rightPad(item.name, 25, 3)}</font>');
|
pl.push('<font color="${color}">${i + 1}. ${isSpectating ? "[S] " : ""}${Util.rightPad(StringTools.htmlEscape(item.name), 25, 3)}</font>');
|
||||||
var connPing = item.us ? (Net.isHost ? 0 : Net.clientConnection.pingTicks) : (item.id == 0 ? 0 : Net.clientIdMap[item.id].pingTicks);
|
var connPing = item.us ? (Net.isHost ? 0 : Net.clientConnection.pingTicks) : (item.id == 0 ? 0 : Net.clientIdMap[item.id].pingTicks);
|
||||||
var pingStatus = "unknown";
|
var pingStatus = "unknown";
|
||||||
if (connPing <= 5)
|
if (connPing <= 5)
|
||||||
|
|
@ -1177,7 +1177,7 @@ class PlayGui {
|
||||||
this.powerupImageScene.setElapsedTime(timeState.dt);
|
this.powerupImageScene.setElapsedTime(timeState.dt);
|
||||||
|
|
||||||
if (this.fpsMeter != null) {
|
if (this.fpsMeter != null) {
|
||||||
this.fpsMeter.text.text = '${Math.floor(ProfilerUI.instance.fps)} fps';
|
this.fpsMeter.text.text = '${Math.floor(ProfilerUI.instance.fps)} FPS';
|
||||||
}
|
}
|
||||||
this.updateMiddleMessages(timeState.dt);
|
this.updateMiddleMessages(timeState.dt);
|
||||||
if (Net.isMP) {
|
if (Net.isMP) {
|
||||||
|
|
|
||||||
|
|
@ -1234,7 +1234,7 @@ class PlayMissionGui extends GuiImage {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
for (score in scoreList) {
|
for (score in scoreList) {
|
||||||
sFmt.push('${i}.
|
sFmt.push('${i}.
|
||||||
<offset value="15">${score.name.substr(0, 30)}</offset>
|
<offset value="15">${StringTools.htmlEscape(score.name.substr(0, 30))}</offset>
|
||||||
<offset value="215">${Util.formatTime(score.score)}</offset>
|
<offset value="215">${Util.formatTime(score.score)}</offset>
|
||||||
<offset value="279"><img src="${platformToString(score.platform)}"/></offset>
|
<offset value="279"><img src="${platformToString(score.platform)}"/></offset>
|
||||||
${score.rewind == 1 ? '<offset value="299"><img src="rewind"/></offset> ' : ""}');
|
${score.rewind == 1 ? '<offset value="299"><img src="rewind"/></offset> ' : ""}');
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ class HuntMode extends NullMode {
|
||||||
}
|
}
|
||||||
} else if (element._type == MissionElementType.SimGroup) {
|
} else if (element._type == MissionElementType.SimGroup) {
|
||||||
var scanPls = true;
|
var scanPls = true;
|
||||||
if (Net.connectedServerInfo.oldSpawns) {
|
if (Net.isMP && Net.connectedServerInfo.oldSpawns) {
|
||||||
if (element._name.toLowerCase() == "newversion") {
|
if (element._name.toLowerCase() == "newversion") {
|
||||||
// Remove this
|
// Remove this
|
||||||
elToRemove.push(element);
|
elToRemove.push(element);
|
||||||
|
|
@ -121,8 +121,8 @@ class HuntMode extends NullMode {
|
||||||
};
|
};
|
||||||
|
|
||||||
override function getSpawnTransform() {
|
override function getSpawnTransform() {
|
||||||
var idx = Net.connectedServerInfo.competitiveMode ? idealSpawnIndex : Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
var idx = (Net.isMP && Net.connectedServerInfo.competitiveMode) ? idealSpawnIndex : Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
||||||
if (!Net.connectedServerInfo.competitiveMode) {
|
if (!(Net.isMP && Net.connectedServerInfo.competitiveMode)) {
|
||||||
var allTaken = true;
|
var allTaken = true;
|
||||||
for (spw in spawnPointTaken) {
|
for (spw in spawnPointTaken) {
|
||||||
if (!spw) {
|
if (!spw) {
|
||||||
|
|
@ -370,7 +370,7 @@ class HuntMode extends NullMode {
|
||||||
var gemPos = gemElem.gem.getAbsPos().getPosition();
|
var gemPos = gemElem.gem.getAbsPos().getPosition();
|
||||||
|
|
||||||
if (level.mission.missionInfo.game == "PlatinumQuest") {
|
if (level.mission.missionInfo.game == "PlatinumQuest") {
|
||||||
if (Net.connectedServerInfo.oldSpawns) {
|
if (Net.isMP && Net.connectedServerInfo.oldSpawns) {
|
||||||
// Spawn chances!
|
// Spawn chances!
|
||||||
var chance = switch (gemElem.gem.gemColor.toLowerCase()) {
|
var chance = switch (gemElem.gem.gemColor.toLowerCase()) {
|
||||||
case "red.gem":
|
case "red.gem":
|
||||||
|
|
@ -836,7 +836,7 @@ class HuntMode extends NullMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
override function update(t:src.TimeState) {
|
override function update(t:src.TimeState) {
|
||||||
if (Net.connectedServerInfo.competitiveMode) {
|
if (this.level.isMultiplayer && Net.connectedServerInfo.competitiveMode) {
|
||||||
if (competitiveTimerStartTicks != 0) {
|
if (competitiveTimerStartTicks != 0) {
|
||||||
var currentTime = Net.isHost ? t.ticks : @:privateAccess level.marble.serverTicks;
|
var currentTime = Net.isHost ? t.ticks : @:privateAccess level.marble.serverTicks;
|
||||||
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class InputBitStream {
|
||||||
this.shift = 0;
|
this.shift = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readBits(bits:Int = 8) {
|
inline function readBits(bits:Int = 8) {
|
||||||
if (this.shift + bits >= 8) {
|
if (this.shift + bits >= 8) {
|
||||||
var extra = (this.shift + bits) % 8;
|
var extra = (this.shift + bits) % 8;
|
||||||
var remain = bits - extra;
|
var remain = bits - extra;
|
||||||
|
|
@ -37,7 +37,7 @@ class InputBitStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readInt(bits:Int = 32) {
|
public inline function readInt(bits:Int = 32) {
|
||||||
var value = 0;
|
var value = 0;
|
||||||
var shift = 0;
|
var shift = 0;
|
||||||
while (bits > 0) {
|
while (bits > 0) {
|
||||||
|
|
@ -48,39 +48,40 @@ class InputBitStream {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFlag() {
|
public inline function readFlag() {
|
||||||
return readInt(1) != 0;
|
return readInt(1) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readByte() {
|
public inline function readByte() {
|
||||||
return readInt(8);
|
return readInt(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readUInt16() {
|
public inline function readUInt16() {
|
||||||
return readInt(16);
|
return readInt(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readInt32() {
|
public inline function readInt32() {
|
||||||
return readInt(32);
|
return readInt(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readFloat() {
|
public inline function readFloat() {
|
||||||
return FPHelper.i32ToFloat(readInt32());
|
return FPHelper.i32ToFloat(readInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readDouble() {
|
public inline function readDouble() {
|
||||||
var lo = readInt32();
|
var lo = readInt32();
|
||||||
var hi = readInt32();
|
var hi = readInt32();
|
||||||
return FPHelper.i64ToDouble(lo, hi);
|
return FPHelper.i64ToDouble(lo, hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readString() {
|
public inline function readString() {
|
||||||
var length = readUInt16();
|
var length = readUInt16();
|
||||||
var str = "";
|
var str = "";
|
||||||
|
var buf = new StringBuf();
|
||||||
for (i in 0...length) {
|
for (i in 0...length) {
|
||||||
str += String.fromCharCode(readByte());
|
buf.addChar(readByte());
|
||||||
}
|
}
|
||||||
return str;
|
return buf.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +100,7 @@ class OutputBitStream {
|
||||||
this.lastByte = 0;
|
this.lastByte = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeBits(value:Int, bits:Int) {
|
inline function writeBits(value:Int, bits:Int) {
|
||||||
value = value & (0xFF >> (8 - bits));
|
value = value & (0xFF >> (8 - bits));
|
||||||
if (this.shift + bits >= 8) {
|
if (this.shift + bits >= 8) {
|
||||||
var extra = (shift + bits) % 8;
|
var extra = (shift + bits) % 8;
|
||||||
|
|
@ -118,7 +119,7 @@ class OutputBitStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeInt(value:Int, bits:Int = 32) {
|
public inline function writeInt(value:Int, bits:Int = 32) {
|
||||||
while (bits > 0) {
|
while (bits > 0) {
|
||||||
this.writeBits(value & 0xFF, bits < 8 ? bits : 8);
|
this.writeBits(value & 0xFF, bits < 8 ? bits : 8);
|
||||||
value >>= 8;
|
value >>= 8;
|
||||||
|
|
@ -126,39 +127,39 @@ class OutputBitStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeFlag(value:Bool) {
|
public inline function writeFlag(value:Bool) {
|
||||||
writeInt(value ? 1 : 0, 1);
|
writeInt(value ? 1 : 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeByte(value:Int) {
|
public inline function writeByte(value:Int) {
|
||||||
writeInt(value, 8);
|
writeInt(value, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeUInt16(value:Int) {
|
public inline function writeUInt16(value:Int) {
|
||||||
writeInt(value, 16);
|
writeInt(value, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeInt32(value:Int) {
|
public inline function writeInt32(value:Int) {
|
||||||
writeInt(value, 32);
|
writeInt(value, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBytes() {
|
public inline function getBytes() {
|
||||||
this.data.writeByte(this.lastByte);
|
this.data.writeByte(this.lastByte);
|
||||||
return this.data.getBytes();
|
return this.data.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeFloat(value:Float) {
|
public inline function writeFloat(value:Float) {
|
||||||
writeInt(FPHelper.floatToI32(value), 32);
|
writeInt(FPHelper.floatToI32(value), 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeString(value:String) {
|
public inline function writeString(value:String) {
|
||||||
writeUInt16(value.length);
|
writeUInt16(value.length);
|
||||||
for (i in 0...value.length) {
|
for (i in 0...value.length) {
|
||||||
writeByte(StringTools.fastCodeAt(value, i));
|
writeByte(StringTools.fastCodeAt(value, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeDouble(value:Float) {
|
public inline function writeDouble(value:Float) {
|
||||||
var i64 = FPHelper.doubleToI64(value);
|
var i64 = FPHelper.doubleToI64(value);
|
||||||
writeInt32(i64.low);
|
writeInt32(i64.low);
|
||||||
writeInt32(i64.high);
|
writeInt32(i64.high);
|
||||||
|
|
|
||||||
|
|
@ -46,41 +46,61 @@ class MarblePredictionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeState(marble:Marble, tick:Int) {
|
public function storeState(marble:Marble, tick:Int) {
|
||||||
var state = new MarblePrediction(marble, tick);
|
var arr = ensureHistory(marble);
|
||||||
if (predictions.exists(marble)) {
|
truncateFromTick(arr, tick);
|
||||||
var arr = predictions[marble];
|
arr.push(new MarblePrediction(marble, tick));
|
||||||
while (arr.length != 0 && arr[0].tick >= tick)
|
|
||||||
arr.shift();
|
|
||||||
arr.push(state);
|
|
||||||
} else {
|
|
||||||
predictions.set(marble, [state]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function retrieveState(marble:Marble, tick:Int) {
|
public function retrieveState(marble:Marble, tick:Int) {
|
||||||
if (predictions.exists(marble)) {
|
var arr = predictions.get(marble);
|
||||||
var arr = predictions[marble];
|
if (arr == null)
|
||||||
while (arr.length != 0 && arr[0].tick < tick)
|
|
||||||
arr.shift();
|
|
||||||
if (arr.length == 0)
|
|
||||||
return null;
|
|
||||||
var p = arr[0];
|
|
||||||
if (p.tick == tick)
|
|
||||||
return p;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
dropBeforeTick(arr, tick);
|
||||||
|
return (arr.length != 0 && arr[0].tick == tick) ? arr[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clearStatesAfterTick(marble:Marble, tick:Int) {
|
public function clearStatesAfterTick(marble:Marble, tick:Int) {
|
||||||
if (predictions.exists(marble)) {
|
var arr = predictions.get(marble);
|
||||||
var arr = predictions[marble];
|
if (arr != null)
|
||||||
while (arr.length != 0 && arr[arr.length - 1].tick >= tick)
|
truncateFromTick(arr, tick);
|
||||||
arr.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeMarbleFromPrediction(marble:Marble) {
|
public function removeMarbleFromPrediction(marble:Marble) {
|
||||||
this.predictions.remove(marble);
|
this.predictions.remove(marble);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline function ensureHistory(marble:Marble) {
|
||||||
|
var arr = predictions.get(marble);
|
||||||
|
if (arr == null) {
|
||||||
|
arr = [];
|
||||||
|
predictions.set(marble, arr);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function dropBeforeTick(arr:Array<MarblePrediction>, tick:Int) {
|
||||||
|
var idx = lowerBound(arr, tick);
|
||||||
|
if (idx > 0)
|
||||||
|
arr.splice(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function truncateFromTick(arr:Array<MarblePrediction>, tick:Int) {
|
||||||
|
var idx = lowerBound(arr, tick);
|
||||||
|
if (idx < arr.length)
|
||||||
|
arr.splice(idx, arr.length - idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline function lowerBound(arr:Array<MarblePrediction>, tick:Int) {
|
||||||
|
var lo = 0;
|
||||||
|
var hi = arr.length;
|
||||||
|
while (lo < hi) {
|
||||||
|
var mid = (lo + hi) >> 1;
|
||||||
|
if (arr[mid].tick < tick)
|
||||||
|
lo = mid + 1;
|
||||||
|
else
|
||||||
|
hi = mid;
|
||||||
|
}
|
||||||
|
return lo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class MasterServerClient {
|
||||||
#if js
|
#if js
|
||||||
static var serverIp = "wss://mbpmaster.randomityguy.me:8443";
|
static var serverIp = "wss://mbpmaster.randomityguy.me:8443";
|
||||||
#else
|
#else
|
||||||
static var serverIp = "ws://89.58.58.191:8084";
|
static var serverIp = "ws://51.75.65.148:8084";
|
||||||
#end
|
#end
|
||||||
public static var instance:MasterServerClient;
|
public static var instance:MasterServerClient;
|
||||||
|
|
||||||
|
|
@ -102,7 +102,6 @@ class MasterServerClient {
|
||||||
instance = null;
|
instance = null;
|
||||||
}
|
}
|
||||||
#if hl
|
#if hl
|
||||||
stopMutex.acquire();
|
|
||||||
stopping = true;
|
stopping = true;
|
||||||
stopMutex.release();
|
stopMutex.release();
|
||||||
if (myToken == wsToken) {
|
if (myToken == wsToken) {
|
||||||
|
|
@ -195,6 +194,14 @@ class MasterServerClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function requestTurnCredentials() {
|
||||||
|
if (instance != null && instance.open) {
|
||||||
|
instance.queueMessage(Json.stringify({
|
||||||
|
type: "turn_credentials"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function queueMessage(m:String) {
|
function queueMessage(m:String) {
|
||||||
#if hl
|
#if hl
|
||||||
toSend.add(m);
|
toSend.add(m);
|
||||||
|
|
@ -307,8 +314,11 @@ class MasterServerClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (conts.type == "turnserver") {
|
if (conts.type == "turn_credentials") {
|
||||||
Net.turnServer = conts.server; // Turn server!
|
Net.turnServers = conts.turn_servers;
|
||||||
|
if (@:privateAccess Net.onTurnServersReceived != null) {
|
||||||
|
@:privateAccess Net.onTurnServersReceived();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ class MoveManager {
|
||||||
return netMove;
|
return netMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyMove(to:Int, from:Int) {
|
inline function copyMove(to:Int, from:Int) {
|
||||||
queuedMoves[to].move = queuedMoves[from].move;
|
queuedMoves[to].move = queuedMoves[from].move;
|
||||||
queuedMoves[to].motionDir.load(queuedMoves[from].motionDir);
|
queuedMoves[to].motionDir.load(queuedMoves[from].motionDir);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,9 @@ class Net {
|
||||||
|
|
||||||
static var stunServers = ["stun:stun.l.google.com:19302"];
|
static var stunServers = ["stun:stun.l.google.com:19302"];
|
||||||
|
|
||||||
public static var turnServer:String = "";
|
public static var turnServers:Array<String> = [];
|
||||||
|
|
||||||
|
static var onTurnServersReceived:Null<() -> Void> = null;
|
||||||
|
|
||||||
public static function hostServer(name:String, description:String, maxPlayers:Int, password:String, onHosted:() -> Void) {
|
public static function hostServer(name:String, description:String, maxPlayers:Int, password:String, onHosted:() -> Void) {
|
||||||
serverInfo = new ServerInfo(name, Settings.highscoreName, description, 1, maxPlayers, password, "LOBBY", getPlatform());
|
serverInfo = new ServerInfo(name, Settings.highscoreName, description, 1, maxPlayers, password, "LOBBY", getPlatform());
|
||||||
|
|
@ -128,8 +130,16 @@ class Net {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function addClientFromSdp(sdpString:String, onFinishSdp:String->Void) {
|
public static function addClientFromSdp(sdpString:String, onFinishSdp:String->Void, turnTried:Bool = false) {
|
||||||
var peer = new RTCPeerConnection(stunServers, "0.0.0.0");
|
if (Net.turnServers.length == 0 && !turnTried) {
|
||||||
|
MasterServerClient.requestTurnCredentials();
|
||||||
|
Net.onTurnServersReceived = () -> {
|
||||||
|
Net.onTurnServersReceived = null;
|
||||||
|
addClientFromSdp(sdpString, onFinishSdp, true);
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var peer = new RTCPeerConnection(stunServers.concat(Net.turnServers), "0.0.0.0");
|
||||||
var sdpObj = Json.parse(sdpString);
|
var sdpObj = Json.parse(sdpString);
|
||||||
peer.setRemoteDescription(sdpObj.sdp, sdpObj.type);
|
peer.setRemoteDescription(sdpObj.sdp, sdpObj.type);
|
||||||
addClient(peer, onFinishSdp);
|
addClient(peer, onFinishSdp);
|
||||||
|
|
@ -212,9 +222,18 @@ class Net {
|
||||||
clientIdMap[id] = ghost;
|
clientIdMap[id] = ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function joinServer(serverName:String, password:String, connectedCb:() -> Void) {
|
public static function joinServer(serverName:String, password:String, connectedCb:() -> Void, turnTried:Bool = false) {
|
||||||
MasterServerClient.connectToMasterServer(() -> {
|
MasterServerClient.connectToMasterServer(() -> {
|
||||||
client = new RTCPeerConnection(stunServers, "0.0.0.0");
|
if (Net.turnServers.length == 0 && !turnTried) {
|
||||||
|
MasterServerClient.requestTurnCredentials();
|
||||||
|
Net.onTurnServersReceived = () -> {
|
||||||
|
Net.onTurnServersReceived = null;
|
||||||
|
joinServer(serverName, password, connectedCb, true);
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client = new RTCPeerConnection(stunServers.concat(Net.turnServers), "0.0.0.0");
|
||||||
var candidates = [];
|
var candidates = [];
|
||||||
|
|
||||||
var closing = false;
|
var closing = false;
|
||||||
|
|
@ -562,7 +581,6 @@ class Net {
|
||||||
serverInfo.players++;
|
serverInfo.players++;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInfo.players++;
|
|
||||||
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
|
MasterServerClient.instance.sendServerInfo(serverInfo); // notify the server of the new player
|
||||||
|
|
||||||
if (MarbleGame.canvas.content is MPPlayMissionGui) {
|
if (MarbleGame.canvas.content is MPPlayMissionGui) {
|
||||||
|
|
|
||||||
|
|
@ -154,13 +154,13 @@ class RewindManager {
|
||||||
|| level.marble.currentUp.z != rf.currentUp.z) {
|
|| level.marble.currentUp.z != rf.currentUp.z) {
|
||||||
level.setUp(level.marble, rf.currentUp, level.timeState);
|
level.setUp(level.marble, rf.currentUp, level.timeState);
|
||||||
// Hacky things
|
// Hacky things
|
||||||
@:privateAccess level.orientationChangeTime = level.timeState.currentAttemptTime - 300;
|
@:privateAccess level.orientationChangeTime = level.timeState.currentAttemptTime - 0.3;
|
||||||
var oldorient = level.newOrientationQuat;
|
var oldorient = level.newOrientationQuat;
|
||||||
level.newOrientationQuat = @:privateAccess level.oldOrientationQuat;
|
level.newOrientationQuat = @:privateAccess level.oldOrientationQuat;
|
||||||
@:privateAccess level.oldOrientationQuat = oldorient;
|
@:privateAccess level.oldOrientationQuat = oldorient;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gravitycompletion = Util.clamp((level.timeState.currentAttemptTime - @:privateAccess level.orientationChangeTime) / 300, 0, 1);
|
var gravitycompletion = Util.clamp((level.timeState.currentAttemptTime - @:privateAccess level.orientationChangeTime) / 0.3, 0, 1);
|
||||||
if (gravitycompletion == 0) {
|
if (gravitycompletion == 0) {
|
||||||
level.newOrientationQuat = @:privateAccess level.oldOrientationQuat;
|
level.newOrientationQuat = @:privateAccess level.oldOrientationQuat;
|
||||||
@:privateAccess level.orientationChangeTime = -1e8;
|
@:privateAccess level.orientationChangeTime = -1e8;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class CameraInput {
|
||||||
var identifier:Int = -1;
|
var identifier:Int = -1;
|
||||||
|
|
||||||
public var enabled = false;
|
public var enabled = false;
|
||||||
|
public var pressed = false;
|
||||||
|
|
||||||
var added = false;
|
var added = false;
|
||||||
|
|
||||||
|
|
@ -36,8 +37,6 @@ class CameraInput {
|
||||||
this.collider.horizSizing = Width;
|
this.collider.horizSizing = Width;
|
||||||
this.collider.vertSizing = Height;
|
this.collider.vertSizing = Height;
|
||||||
|
|
||||||
var pressed = false;
|
|
||||||
|
|
||||||
var prevMouse = new Vector(0, 0);
|
var prevMouse = new Vector(0, 0);
|
||||||
interactive.onPush = (e) -> {
|
interactive.onPush = (e) -> {
|
||||||
e.propagate = true;
|
e.propagate = true;
|
||||||
|
|
@ -87,14 +86,24 @@ class CameraInput {
|
||||||
if (jumpcam) {
|
if (jumpcam) {
|
||||||
scaleFactor /= Settings.touchSettings.buttonJoystickMultiplier;
|
scaleFactor /= Settings.touchSettings.buttonJoystickMultiplier;
|
||||||
}
|
}
|
||||||
if (Math.abs(delta.x) < 0.05)
|
var inpX = delta.x / scaleFactor;
|
||||||
delta.x = 0;
|
var inpY = delta.y / scaleFactor;
|
||||||
if (Math.abs(delta.y) < 0.05)
|
|
||||||
delta.y = 0;
|
if (jumpcam) {
|
||||||
MarbleGame.instance.world.marble.camera.orbit(applyNonlinearScale(delta.x / scaleFactor), applyNonlinearScale(delta.y / scaleFactor), true);
|
if (Math.abs(inpX) < 1.3)
|
||||||
if (delta.x != 0)
|
inpX = 0;
|
||||||
|
if (Math.abs(inpY) < 1.3)
|
||||||
|
inpY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dt = MarbleGame.instance.world.timeState.dt;
|
||||||
|
|
||||||
|
MarbleGame.instance.world.marble.camera.orbit(applyNonlinearScale((inpX / dt) * (1 / 60.0)) * (1 / 60.0) * 35,
|
||||||
|
applyNonlinearScale((inpY / dt) * (1 / 60.0)) * (1 / 60.0) * 35, true);
|
||||||
|
|
||||||
|
if (inpX != 0)
|
||||||
prevMouse.x = e.relX;
|
prevMouse.x = e.relX;
|
||||||
if (delta.y != 0)
|
if (inpY != 0)
|
||||||
prevMouse.y = e.relY;
|
prevMouse.y = e.relY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ class PauseButton extends TouchButton {
|
||||||
|
|
||||||
this.onClick = () -> {
|
this.onClick = () -> {
|
||||||
if (MarbleGame.instance.world != null && @:privateAccess !MarbleGame.instance.paused) {
|
if (MarbleGame.instance.world != null && @:privateAccess !MarbleGame.instance.paused) {
|
||||||
@:privateAccess MarbleGame.instance.paused = true;
|
|
||||||
MarbleGame.instance.handlePauseGame();
|
MarbleGame.instance.handlePauseGame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class TouchEventState {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TouchInput {
|
class TouchInput {
|
||||||
var cameraInput:CameraInput;
|
public var cameraInput:CameraInput;
|
||||||
|
|
||||||
public var movementInput:MovementInput;
|
public var movementInput:MovementInput;
|
||||||
|
|
||||||
|
|
|
||||||