initial commit
This commit is contained in:
		
							
								
								
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| tags | ||||
| *.log | ||||
| *.tar.xz | ||||
| *.tar.gz | ||||
| *.zip | ||||
| /oppai | ||||
| *.json | ||||
| *.obj | ||||
| *.exe | ||||
| *.swp | ||||
| *.so | ||||
| *.dll | ||||
| *.lib | ||||
| *.exp | ||||
| /test/test_suite | ||||
| /test/oppai_test | ||||
| /swig/**/*.c | ||||
| /swig/*/*.i | ||||
| /swig/python/oppai.egg-info | ||||
| /swig/python/build | ||||
| /swig/python/oppai.py | ||||
| *.whl | ||||
| *.pyc | ||||
							
								
								
									
										29
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| language: c | ||||
|  | ||||
| matrix: | ||||
|   include: | ||||
|   - os: linux | ||||
|     dist: precise | ||||
|   - os: linux | ||||
|     dist: trusty | ||||
|   - os: osx | ||||
|  | ||||
| install: true | ||||
| cache: | ||||
|   directories: | ||||
|   - test/test_suite | ||||
|  | ||||
| script: | ||||
| - ./build | ||||
| - ./libbuild | ||||
| - cd test | ||||
| - ./download_suite | ||||
| - ./build | ||||
| - DYLD_PRINT_LIBRARIES=1 DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 | ||||
|   DYLD_PRINT_RPATHS=1 LD_DEBUG=libs ./oppai_test | ||||
| - wc -c ./oppai_test | ||||
| - LDFLAGS="-loppai" ./build -L.. | ||||
| - LD_LIBRARY_PATH=.. DYLD_LIBRARY_PATH=.. | ||||
|   DYLD_PRINT_LIBRARIES=1 DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 | ||||
|   DYLD_PRINT_RPATHS=1 LD_DEBUG=libs ./oppai_test | ||||
| - wc -c ./oppai_test | ||||
							
								
								
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| ARG PREFIX= | ||||
| FROM ${PREFIX}ubuntu:bionic | ||||
| RUN apt-get update && apt-get install -y \ | ||||
|   gcc musl musl-tools musl-dev git-core file | ||||
| WORKDIR /tmp | ||||
| CMD setarch $arch ./release | ||||
							
								
								
									
										67
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| version: b{build} | ||||
| image: Visual Studio 2017 | ||||
| cache: test/test_suite -> test/suite_url | ||||
| build_script: | ||||
| - ps: >- | ||||
|     function VcVars { | ||||
|         param ([string]$VcPath, [string]$BatName) | ||||
|         Push-Location $VcPath | ||||
|         cmd /c ($BatName + "&set") | | ||||
|         ForEach-Object { | ||||
|             if ($_ -match "=") { | ||||
|                 $v = $_.split("="); set-item -force -path "ENV:\$($v[0])"  -value "$($v[1])" | ||||
|             } | ||||
|         } | ||||
|         Pop-Location | ||||
|     } | ||||
|  | ||||
|  | ||||
|     $VcPath = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build" | ||||
|  | ||||
|  | ||||
|     VcVars $VcPath vcvars32.bat | ||||
|  | ||||
|     .\release.ps1; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|  | ||||
|     VcVars $VcPath vcvars64.bat | ||||
|  | ||||
|     .\release.ps1; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|  | ||||
|     cd .\test | ||||
|  | ||||
|     .\download_suite.ps1 | ||||
|  | ||||
|     .\build.bat; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|     .\oppai_test.exe; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|     Write-Host "bin size: " + (Get-Item '.\oppai_test.exe').length | ||||
|  | ||||
|     dumpbin /dependents .\oppai_test.exe | ||||
|  | ||||
|     .\build.bat ..\oppai.lib; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|     cp ..\oppai.dll . | ||||
|  | ||||
|     .\oppai_test.exe; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
|     Write-Host "bin size: " + (Get-Item '.\oppai_test.exe').length | ||||
|  | ||||
|     dumpbin /dependents .\oppai_test.exe | ||||
| test: off | ||||
| artifacts: | ||||
| - path: oppai-*-windows-*.zip | ||||
|   name: windows-binaries | ||||
| deploy: | ||||
| - provider: GitHub | ||||
|   tag: $(appveyor_repo_tag_name) | ||||
|   release: oppai $(appveyor_repo_tag_name)-$(appveyor_build_version) | ||||
|   description: linux binaries are manually uploaded shortly after the windows release and statically linked against musl libc\n\nwindows binaries should not require the c runtime\n\nx64 and x86_64 mean 64-bit i586 and x86 mean 32-bit\n\nthe binary packages include the source code inside the src directory | ||||
|   auth_token: | ||||
|     secure: k73tV2NZTFp4thujp/KiohNwRwIpWC12gU/qsnfCqlctcC+rqWiDWet3sSAz34gT | ||||
|   artifact: windows-binaries | ||||
|   force_update: true | ||||
|   on: | ||||
|     APPVEYOR_REPO_TAG: true | ||||
							
								
								
									
										6
									
								
								build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								build
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| . "$dir"/cflags | ||||
| $cc $cflags "$@" -DOPPAI_IMPLEMENTATION main.c oppai.c $ldflags -o oppai | ||||
|  | ||||
							
								
								
									
										12
									
								
								build.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								build.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| @echo off | ||||
|  | ||||
| del oppai.exe >nul 2>&1 | ||||
| del main.obj >nul 2>&1 | ||||
| cl  -D_CRT_SECURE_NO_WARNINGS=1 ^ | ||||
|   -DNOMINMAX=1 ^ | ||||
|   -O2 -nologo -MT -Gm- -GR- -EHsc -W4 ^ | ||||
|   -DOPPAI_IMPLEMENTATION ^ | ||||
|   -DOPPAI_STATIC_HEADER ^ | ||||
|   main.c oppai.c ^ | ||||
|   -Feoppai.exe ^ | ||||
|   || EXIT /B 1 | ||||
							
								
								
									
										45
									
								
								cflags
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								cflags
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| cflags="-std=c89 -pedantic" | ||||
| cflags="$cflags -Os" | ||||
| cflags="$cflags -fno-strict-aliasing" | ||||
| cflags="$cflags -Wall" | ||||
| cflags="$cflags -ffunction-sections -fdata-sections" | ||||
| if [ -z $DBGINFO ]; then | ||||
|   cflags="$cflags -g0 -fno-unwind-tables -s" | ||||
|   cflags="$cflags -fno-asynchronous-unwind-tables" | ||||
|   cflags="$cflags -fno-stack-protector" | ||||
| else | ||||
|   cflags="$cflags -g -fsanitize=address -fsanitize=leak " | ||||
|   cflags="$cflags -fsanitize=signed-integer-overflow -fsanitize=undefined -static-libasan" | ||||
| fi | ||||
| if [ $(uname) = "Darwin" ]; then | ||||
|   cflags="$cflags -Wl,-dead_strip" | ||||
| else | ||||
|   cflags="$cflags -Wl,--gc-sections,--build-id=none" | ||||
| fi | ||||
|  | ||||
| ldflags="-lm" | ||||
|  | ||||
| cflags="$cflags $CFLAGS" | ||||
| ldflags="$ldflags $LDFLAGS" | ||||
|  | ||||
| cc="$CC" | ||||
|  | ||||
| if [ $(uname) = "Darwin" ]; then | ||||
|   cc=${cc:-clang} | ||||
| else | ||||
|   cc=${cc:-gcc} | ||||
| fi | ||||
|  | ||||
| uname -a > flags.log | ||||
| echo $cc >> flags.log | ||||
| echo $cflags >> flags.log | ||||
| echo $ldflags >> flags.log | ||||
| $cc --version >> flags.log | ||||
| $cc -dumpmachine >> flags.log | ||||
|  | ||||
| export cflags="$cflags" | ||||
| export ldflags="$ldflags" | ||||
| export cc="$cc" | ||||
|  | ||||
							
								
								
									
										26
									
								
								examples/FFI.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								examples/FFI.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| // csc FFI.cs | ||||
| // FFI.exe /path/to/file.osu | ||||
| // make sure oppai.dll is in the same directory as FFI.exe | ||||
| // see oppai.c for a full list of functions | ||||
|  | ||||
| using System; | ||||
| using System.Runtime.InteropServices; | ||||
|  | ||||
| public class Program | ||||
| { | ||||
|   [DllImport(@"oppai.dll")] | ||||
|   public static extern IntPtr ezpp_new(); | ||||
|  | ||||
|   [DllImport(@"oppai.dll")] | ||||
|   public static extern IntPtr ezpp(IntPtr ez, char[] map); | ||||
|  | ||||
|   [DllImport(@"oppai.dll")] | ||||
|   public static extern float ezpp_pp(IntPtr ez); | ||||
|  | ||||
|   static void Main(string[] args) | ||||
|   { | ||||
|     IntPtr ez = ezpp_new(); | ||||
|     ezpp(ez, args[0].ToCharArray()); | ||||
|     Console.WriteLine($"{ezpp_pp(ez)} pp"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										133
									
								
								examples/binary.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								examples/binary.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| /* | ||||
|  * example of parsing oppai's binary output | ||||
|  * | ||||
|  * gcc binary.c | ||||
|  * oppai /path/to/file.osu -obinary | ./a.out | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| /* | ||||
|  * these are only necessary to ensure endian-ness, if you don't | ||||
|  * care about that you can read values like v = *(int*)p | ||||
|  */ | ||||
|  | ||||
| int read2(char** c) { | ||||
|   unsigned char* p = (unsigned char*)*c; | ||||
|   *c += 2; | ||||
|   return p[0] | (p[1] << 8); | ||||
| } | ||||
|  | ||||
| int read4(char** c) { | ||||
|   unsigned char* p = (unsigned char*)*c; | ||||
|   *c += 4; | ||||
|   return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); | ||||
| } | ||||
|  | ||||
| float read_flt(char** p) { | ||||
|   int v = read4(p); | ||||
|   float* pf = (float*)&v; | ||||
|   return *pf; | ||||
| } | ||||
|  | ||||
| char* read_str(char** p, int* len) { | ||||
|   char* res; | ||||
|   *len = read2(p); | ||||
|   res = *p; | ||||
|   *p += *len + 1; | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| #define MODS_NF (1<<0) | ||||
| #define MODS_EZ (1<<1) | ||||
| #define MODS_HD (1<<3) | ||||
| #define MODS_HR (1<<4) | ||||
| #define MODS_DT (1<<6) | ||||
| #define MODS_HT (1<<8) | ||||
| #define MODS_NC (1<<9) | ||||
| #define MODS_FL (1<<10) | ||||
| #define MODS_SO (1<<12) | ||||
|  | ||||
| int main() { | ||||
|   char buf[8192]; | ||||
|   char* p = buf; | ||||
|   int len; | ||||
|   int result; | ||||
|   int mods; | ||||
|  | ||||
|   memset(buf, 0, sizeof(buf)); | ||||
|  | ||||
|   /* read stdin in binary mode */ | ||||
|   if (!freopen(0, "rb", stdin)) { | ||||
|     perror("freopen"); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   if (!fread(buf, 1, sizeof(buf), stdin)) { | ||||
|     perror("fread"); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   if (strncmp((char const*)p, "binoppai", 8)) { | ||||
|     puts("invalid input"); | ||||
|     return 1; | ||||
|   } | ||||
|   p += 8; | ||||
|  | ||||
|   printf("oppai %d.%d.%d\n", p[0], p[1], p[2]); | ||||
|   p += 3; | ||||
|   puts(""); | ||||
|  | ||||
|   /* error code */ | ||||
|   result = read4(&p); | ||||
|   if (result < 0) { | ||||
|     printf("error %d\n", result); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   printf("artist: %s\n", read_str(&p, &len)); | ||||
|   printf("artist_unicode: %s\n", read_str(&p, &len)); | ||||
|   printf("title: %s\n", read_str(&p, &len)); | ||||
|   printf("title_unicode: %s\n", read_str(&p, &len)); | ||||
|   printf("version: %s\n", read_str(&p, &len)); | ||||
|   printf("creator: %s\n", read_str(&p, &len)); | ||||
|  | ||||
|   mods = read4(&p); | ||||
|   puts(""); | ||||
|   printf("mods: "); | ||||
|   if (mods & MODS_NF) printf("NF"); | ||||
|   if (mods & MODS_EZ) printf("EZ"); | ||||
|   if (mods & MODS_HD) printf("HD"); | ||||
|   if (mods & MODS_HR) printf("HR"); | ||||
|   if (mods & MODS_DT) printf("DT"); | ||||
|   if (mods & MODS_HT) printf("HT"); | ||||
|   if (mods & MODS_NC) printf("NC"); | ||||
|   if (mods & MODS_FL) printf("FL"); | ||||
|   if (mods & MODS_SO) printf("SO"); | ||||
|   puts(""); | ||||
|  | ||||
|   printf("OD%g ", read_flt(&p)); | ||||
|   printf("AR%g ", read_flt(&p)); | ||||
|   printf("CS%g ", read_flt(&p)); | ||||
|   printf("HP%g\n", read_flt(&p)); | ||||
|   printf("%d/%dx\n", read4(&p), read4(&p)); | ||||
|   printf("%d circles ", read2(&p)); | ||||
|   printf("%d sliders ", read2(&p)); | ||||
|   printf("%d spinners\n", read2(&p)); | ||||
|   printf("scorev%d\n", read4(&p)); | ||||
|   puts(""); | ||||
|   printf("%g stars ", read_flt(&p)); | ||||
|   printf("(%g speed, ", read_flt(&p)); | ||||
|   printf("%g aim)\n", read_flt(&p)); | ||||
|   read2(&p); /* legacy */ | ||||
|   read2(&p); /* legacy */ | ||||
|   puts(""); | ||||
|   printf("%g aim pp\n", read_flt(&p)); | ||||
|   printf("%g speed pp\n", read_flt(&p)); | ||||
|   printf("%g acc pp\n", read_flt(&p)); | ||||
|   puts(""); | ||||
|   printf("%g pp\n", read_flt(&p)); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										16
									
								
								examples/min.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								examples/min.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| /* | ||||
|  * gcc min.c -lm | ||||
|  * cat /path/to/file.osu | ./a.out | ||||
|  */ | ||||
|  | ||||
| #define OPPAI_IMPLEMENTATION | ||||
| #include "../oppai.c" | ||||
|  | ||||
| int main() { | ||||
|   ezpp_t ez = ezpp_new(); | ||||
|   ezpp_set_mods(ez, MODS_HD | MODS_DT); | ||||
|   ezpp(ez, "-"); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										61
									
								
								examples/reuse.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								examples/reuse.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /* | ||||
|  * gcc reuse.c -lm | ||||
|  * ./a.out /path/to/file.osu | ||||
|  */ | ||||
|  | ||||
| #define OPPAI_IMPLEMENTATION | ||||
| #include "../oppai.c" | ||||
|  | ||||
| /* | ||||
|  * for better performance, the same instance can be reused | ||||
|  * settings are remembered and map is only reparsed if mods or cs change | ||||
|  */ | ||||
|  | ||||
| int main(int argc, char* argv[]) { | ||||
|   ezpp_t ez = ezpp_new(); | ||||
|   ezpp_set_autocalc(ez, 1); /* autorecalc pp when changing any parameter */ | ||||
|   ezpp(ez, argv[1]); | ||||
|  | ||||
|   puts("---"); | ||||
|   puts("nomod fc"); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("nomod 95% fc"); | ||||
|   ezpp_set_accuracy_percent(ez, 95); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("nomod 1x100 fc"); | ||||
|   ezpp_set_accuracy(ez, 1, 0); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("HD 1x100 1miss 300x"); | ||||
|   ezpp_set_mods(ez, MODS_HD); | ||||
|   ezpp_set_nmiss(ez, 1); | ||||
|   ezpp_set_combo(ez, 300); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("HDDT 1x100 1xmiss 300x"); | ||||
|   ezpp_set_mods(ez, MODS_HD | MODS_DT); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("HDDT 1x100 1xmiss 300x ends at object 300"); | ||||
|   ezpp_set_end(ez, 300); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   puts("HDDT fc"); | ||||
|   ezpp_set_end(ez, 0); | ||||
|   ezpp_set_combo(ez, -1); | ||||
|   ezpp_set_accuracy(ez, 0, 0); | ||||
|   ezpp_set_nmiss(ez, 0); | ||||
|   printf("%gpp\n", ezpp_pp(ez)); | ||||
|   puts("---"); | ||||
|  | ||||
|   ezpp_free(ez); | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										42
									
								
								examples/reuse_mem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								examples/reuse_mem.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #define OPPAI_IMPLEMENTATION | ||||
| #include "oppai.c" | ||||
|  | ||||
| char buf[1000000]; | ||||
| int mods[] = { 0, MODS_HR, MODS_HD | MODS_HR, MODS_DT, MODS_HD | MODS_DT }; | ||||
| #define N_MODS (sizeof(mods) / sizeof(mods[0])) | ||||
|  | ||||
| void print_mods(int mods) { | ||||
|   putchar('+'); | ||||
|   if (!mods) puts("nomod"); | ||||
|   else { | ||||
|     if (mods & MODS_HD) printf("hd"); | ||||
|     if (mods & MODS_HR) printf("hr"); | ||||
|     if (mods & MODS_DT) printf("dt"); | ||||
|     puts(""); | ||||
|   } | ||||
| } | ||||
|  | ||||
| int main(int argc, char* argv[]) { | ||||
|   int i, j, n, acc; | ||||
|   ezpp_t ez = ezpp_new(); | ||||
|   ezpp_set_autocalc(ez, 1); | ||||
|   for (i = 1; i < argc; ++i) { | ||||
|     FILE* f = fopen(argv[i], "r"); | ||||
|     n = fread(buf, 1, sizeof(buf), f); | ||||
|     fclose(f); | ||||
|     ezpp_data(ez, buf, n); | ||||
|     printf("%s - %s [%s]\n", ezpp_artist(ez), ezpp_title(ez), | ||||
|       ezpp_version(ez)); | ||||
|     for (j = 0; j < N_MODS; ++j) { | ||||
|       print_mods(mods[j]); | ||||
|       ezpp_set_mods(ez, mods[j]); | ||||
|       for (acc = 95; acc <= 100; ++acc) { | ||||
|         ezpp_set_accuracy_percent(ez, acc); | ||||
|         printf("%d%% -> %gpp\n", acc, ezpp_pp(ez)); | ||||
|       } | ||||
|     } | ||||
|     puts(""); | ||||
|   } | ||||
|   ezpp_free(ez); | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										37
									
								
								libbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								libbuild
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| . "$dir"/cflags | ||||
|  | ||||
| tmp=$(mktemp -d) | ||||
|  | ||||
| hide_unnecessary_symbols() { | ||||
|   [ ! -d "$tmp" ] && echo "W: couldn't find tmp dir" && return | ||||
|   gcc_syms="$tmp/gcc_exports.sym" | ||||
|   clang_syms="$tmp/clang_exports.list" | ||||
|   code="$tmp/main.c" | ||||
|   echo "int main() { return 0; }" >> "$code" | ||||
|   exports='ezpp ezpp_ errstr oppai_' | ||||
|   ( printf '{global:' | ||||
|     for e in $exports; do | ||||
|       printf '%s;' "$e" | ||||
|     done | ||||
|     printf 'local:*;};' ) | sed 's/_;/_*;/g' >"$gcc_syms" | ||||
|   echo "$exports" | tr ' ' '\n' | sed s/_$/_*/g > "$clang_syms" | ||||
|   for flags in "-Wl,--version-script=$gcc_syms" \ | ||||
|                "-Wl,-exported_symbols_list,$clang_syms" | ||||
|   do | ||||
|     if "$cc" $flags "$code" -o /dev/null >/dev/null 2>&1; then | ||||
|       ldflags="$ldflags $flags" | ||||
|       return | ||||
|     fi | ||||
|   done | ||||
|   echo "W: can't figure out how to hide unnecessary symbols" | ||||
| } | ||||
|  | ||||
| hide_unnecessary_symbols | ||||
|  | ||||
| $cc -shared $cflags -DOPPAI_EXPORT \ | ||||
|   "$@" oppai.c $ldflags -fpic -o liboppai.so | ||||
|  | ||||
| [ -d "$tmp" ] && rm -rf "$tmp" | ||||
							
								
								
									
										14
									
								
								libbuild.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								libbuild.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| @echo off | ||||
|  | ||||
| del oppai.dll >nul 2>&1 | ||||
| del oppai.obj >nul 2>&1 | ||||
| del oppai.exp >nul 2>&1 | ||||
| echo compiling | ||||
| cl ^ | ||||
|   /c /O2 /nologo /Gm- /GR- /EHsc /W4 /Gz ^ | ||||
|   /D_CRT_SECURE_NO_WARNINGS=1 /DNOMINMAX=1 ^ | ||||
|   /DOPPAI_EXPORT /D_WINDLL /D_USRDLL ^ | ||||
|   oppai.c ^ | ||||
|   || EXIT /B 1 | ||||
| echo making dll | ||||
| link /OUT:oppai.dll /IMPLIB:oppai.lib /NOLOGO /DLL oppai.obj | ||||
							
								
								
									
										966
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										966
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,966 @@ | ||||
| /* | ||||
|  * this is free and unencumbered software released into the | ||||
|  * public domain. | ||||
|  * | ||||
|  * refer to the attached UNLICENSE or http://unlicense.org/ | ||||
|  * ---------------------------------------------------------------- | ||||
|  * command line interface for oppai | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include <ctype.h> | ||||
| #undef OPPAI_EXPORT | ||||
| #undef OPPAI_IMPLEMENTATION | ||||
| #include "oppai.c" | ||||
|  | ||||
| char* me = "oppai"; | ||||
|  | ||||
| #define al_round(x) (float)floor((x) + 0.5f) | ||||
| #define al_min(a, b) ((a) < (b) ? (a) : (b)) | ||||
| #define al_max(a, b) ((a) > (b) ? (a) : (b)) | ||||
| #define twodec(x) (al_round((x) * 100.0f) / 100.0f) | ||||
| #define array_len(x) (sizeof(x) / sizeof((x)[0])) | ||||
|  | ||||
| static | ||||
| float get_inf() { | ||||
|   static unsigned raw = 0x7F800000; | ||||
|   float* p = (float*)&raw; | ||||
|   return *p; | ||||
| } | ||||
|  | ||||
| static | ||||
| int is_nan(float b) { | ||||
|   int* p = (int*)&b; | ||||
|   return ( | ||||
|     (*p > 0x7F800000 && *p < 0x80000000) || | ||||
|     (*p > 0x7FBFFFFF && *p <= 0xFFFFFFFF) | ||||
|   ); | ||||
| } | ||||
|  | ||||
| static | ||||
| int info(char* fmt, ...) { | ||||
|   int res; | ||||
|   va_list va; | ||||
|   va_start(va, fmt); | ||||
|   res = vfprintf(stderr, fmt, va); | ||||
|   va_end(va); | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| void usage() { | ||||
|   /* logo by flesnuk https://github.com/Francesco149/oppai-ng/issues/10 */ | ||||
|  | ||||
|   info( | ||||
|     "     /\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb/ /\xe2\x8e\xbb\xe2" | ||||
|     "\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb/ /\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2" | ||||
|     "\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb/ /\xe2\x8e" | ||||
|     "\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2" | ||||
|     "\x8e\xbb\xe2\x8e\xbb/ /\xe2\x8e\xbb/      /\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\\    /\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e" | ||||
|     "\xbb\xe2\x8e\xbb/\n    / /\xe2\x8e\xbb\xe2\x8e\xbb\xe2" | ||||
|     "\x8e\xbb/ / / /\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb/ / " | ||||
|   ); | ||||
|  | ||||
|   info( | ||||
|     "/ /\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb/ /  \xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb/ / / / " | ||||
|     "___  / /\xe2\x8e\xbb\xe2\x8e\xbb\\ \\  / /\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb\xe2\x8e\xbb/ /\n   / /   / / / /   / / / /" | ||||
|     "   / / /\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb\xe2\x8e\xbb" | ||||
|     "\xe2\x8e\xbb/ / / / /__/ / /   / / / /   / /\n  / /___/ " | ||||
|     "/ / /___/ / / /___/ / / /___/ / / /      / /   / / / /__" | ||||
|     "_/ /\n /_______/ / ______/ / ______/ /_______/ /_/      " | ||||
|     "/_/   /_/ /_____  /\n          / /       / /            " | ||||
|     "                              / / \n         / /       /" | ||||
|     " /                                    /\xe2\x8e\xbb/___/" | ||||
|     " / \n        /_/       /_/                              " | ||||
|     "      /_______/" | ||||
|   ); | ||||
|  | ||||
|   info("\n\n"); | ||||
|   info("usage: %s /path/to/file.osu parameters\n\n", me); | ||||
|  | ||||
|   info( | ||||
|     "set filename to '-' to read from standard input\n" | ||||
|     "all parameters are case insensitive\n" | ||||
|     "\n" | ||||
|     "-o[output_module]\n" | ||||
|     "  output module. pass ? to list modules (oppai - -o?)\n" | ||||
|     "  default: text\n" | ||||
|     "  example: -ojson\n" | ||||
|     "\n" | ||||
|     "[accuracy]%%\n" | ||||
|     "  accuracy percentage\n" | ||||
|     "  default: 100%%\n" | ||||
|     "  example: 95%%\n" | ||||
|     "\n" | ||||
|     "[n]x100\n" | ||||
|     "  amount of 100s\n" | ||||
|     "  default: 0\n" | ||||
|     "  example: 2x100\n" | ||||
|     "\n" | ||||
|   ); | ||||
|  | ||||
|   info( | ||||
|     "[n]x50\n" | ||||
|     "  amount of 50s\n" | ||||
|     "  default: 0\n" | ||||
|     "  example: 2x50\n" | ||||
|     "\n" | ||||
|     "[n]xm\n" | ||||
|     "[n]xmiss\n" | ||||
|     "[n]m\n" | ||||
|     "  amount of misses\n" | ||||
|     "  default: 0\n" | ||||
|     "  example: 1m\n" | ||||
|     "\n" | ||||
|     "[combo]x\n" | ||||
|     "  highest combo achieved\n" | ||||
|     "  default: full combo (calculated from map data)\n" | ||||
|     "  example: 500x\n" | ||||
|     "\n" | ||||
|     "scorev[n]\n" | ||||
|     "  scoring system\n" | ||||
|     "  default: 1\n" | ||||
|     "  example: scorev2\n" | ||||
|     "\n" | ||||
|   ); | ||||
|  | ||||
|   info( | ||||
|     "ar[n]\n" | ||||
|     "  base approach rate override\n" | ||||
|     "  default: map's base approach rate\n" | ||||
|     "  example: AR5\n" | ||||
|     "\n" | ||||
|     "od[n]\n" | ||||
|     "  base overall difficulty override\n" | ||||
|     "  default: map's base overall difficulty\n" | ||||
|     "  example: OD10\n" | ||||
|     "\n" | ||||
|     "cs[n]\n" | ||||
|     "  base circle size override\n" | ||||
|     "  default: map's base circle size\n" | ||||
|     "  example: CS6.5\n" | ||||
|     "\n" | ||||
|   ); | ||||
|  | ||||
|   info( | ||||
|     "-m[n]\n" | ||||
|     "  gamemode id override for converted maps\n" | ||||
|     "  default: uses the map's gamemode\n" | ||||
|     "  example: -m1\n" | ||||
|     "\n" | ||||
|     "-taiko\n" | ||||
|     "  forces gamemode to taiko for converted maps\n" | ||||
|     "  default: disabled\n" | ||||
|     "\n" | ||||
|     "-touch\n" | ||||
|     "  calculates pp for touchscreen / touch devices. can \n" | ||||
|     "  also be specified as mod TD\n" | ||||
|     "\n" | ||||
|     "[n]speed\n" | ||||
|     "  override speed stars. " | ||||
|     "useful for maps with incorrect star rating\n" | ||||
|     "  default: uses computed speed stars\n" | ||||
|     "  example: 3.5speed\n" | ||||
|     "\n" | ||||
|   ); | ||||
|  | ||||
|   info( | ||||
|     "[n]aim\n" | ||||
|     "  override aim stars. " | ||||
|     "useful for maps with incorrect star rating\n" | ||||
|     "  default: uses computed aim stars\n" | ||||
|     "  example: 2.4aim\n" | ||||
|     "\n" | ||||
|     "-end[n]\n" | ||||
|     "  cuts map to a certain number of objects\n" | ||||
|   ); | ||||
| } | ||||
|  | ||||
| #define output_sig(name) void name(int result, ezpp_t ez, char* mods_str) | ||||
|  | ||||
| typedef output_sig(fnoutput); | ||||
|  | ||||
| /* null output --------------------------------------------------------- */ | ||||
|  | ||||
| /* stdout must be left alone, outputting to stderr is fine tho */ | ||||
| output_sig(output_null) { (void)result; (void)ez; (void)mods_str; } | ||||
|  | ||||
| /* text output --------------------------------------------------------- */ | ||||
|  | ||||
| #define ASCIIPLT_W 51 | ||||
|  | ||||
| void asciiplt(float (* getvalue)(void* data, int i), int n, void* data) { | ||||
|   static char* charset[] = { | ||||
| #ifdef OPPAI_UTF8GRAPH | ||||
|     "\xe2\x96\x81", | ||||
|     "\xe2\x96\x82", | ||||
|     "\xe2\x96\x83", | ||||
|     "\xe2\x96\x84", | ||||
|     "\xe2\x96\x85", | ||||
|     "\xe2\x96\x86", | ||||
|     "\xe2\x96\x87", | ||||
|     "\xe2\x96\x88" | ||||
| #else | ||||
|     " ", "_", ".", "-", "^" | ||||
| #endif | ||||
|   }; | ||||
|  | ||||
|   static int charsetsize = array_len(charset); | ||||
|  | ||||
|   float values[ASCIIPLT_W]; | ||||
|   float minval = (float)get_inf(); | ||||
|   float maxval = (float)-get_inf(); | ||||
|   float range; | ||||
|   int i; | ||||
|   int chunksize; | ||||
|   int w = al_min(ASCIIPLT_W, n); | ||||
|  | ||||
|   memset(values, 0, sizeof(values)); | ||||
|   chunksize = (int)ceil((float)n / w); | ||||
|  | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     int chunki = i / chunksize; | ||||
|     values[chunki] = al_max(values[chunki], getvalue(data, i)); | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     int chunki = i / chunksize; | ||||
|     maxval = al_max(maxval, values[chunki]); | ||||
|     minval = al_min(minval, values[chunki]); | ||||
|   } | ||||
|  | ||||
|   range = al_max(0.00001f, maxval - minval); | ||||
|  | ||||
|   for (i = 0; i < w; ++i) { | ||||
|     int chari = (int)(((values[i] - minval) / range) * charsetsize); | ||||
|     chari = al_max(0, al_min(chari, charsetsize - 1)); | ||||
|     printf("%s", charset[chari]); | ||||
|   } | ||||
|  | ||||
|   puts(""); | ||||
| } | ||||
|  | ||||
| float getaim(void* data, int i) { | ||||
|   ezpp_t ez = data; | ||||
|   return ezpp_strain_at(ez, i, DIFF_AIM); | ||||
| } | ||||
|  | ||||
| float getspeed(void* data, int i) { | ||||
|   ezpp_t ez = data; | ||||
|   return ezpp_strain_at(ez, i, DIFF_SPEED); | ||||
| } | ||||
|  | ||||
| output_sig(output_text) { | ||||
|   float ar, od, cs, hp, stars, aim_stars, speed_stars, accuracy_percent; | ||||
|   float pp, aim_pp, speed_pp, acc_pp; | ||||
|  | ||||
|   if (result < 0) { | ||||
|     puts(errstr(result)); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   printf("%s - %s ", ezpp_artist(ez), ezpp_title(ez)); | ||||
|  | ||||
|   if (strcmp(ezpp_artist(ez), ezpp_artist_unicode(ez)) || | ||||
|     strcmp(ezpp_title(ez), ezpp_title_unicode(ez))) | ||||
|   { | ||||
|     printf("(%s - %s) ", ezpp_artist_unicode(ez), ezpp_title_unicode(ez)); | ||||
|   } | ||||
|  | ||||
|   printf("[%s] mapped by %s ", ezpp_version(ez), ezpp_creator(ez)); | ||||
|   puts("\n"); | ||||
|  | ||||
|   ar = twodec(ezpp_ar(ez)); | ||||
|   od = twodec(ezpp_od(ez)); | ||||
|   cs = twodec(ezpp_cs(ez)); | ||||
|   hp = twodec(ezpp_hp(ez)); | ||||
|   stars = twodec(ezpp_stars(ez)); | ||||
|   aim_stars = twodec(ezpp_aim_stars(ez)); | ||||
|   speed_stars = twodec(ezpp_speed_stars(ez)); | ||||
|   accuracy_percent = twodec(ezpp_accuracy_percent(ez)); | ||||
|   pp = twodec(ezpp_pp(ez)); | ||||
|   aim_pp = twodec(ezpp_aim_pp(ez)); | ||||
|   speed_pp = twodec(ezpp_speed_pp(ez)); | ||||
|   acc_pp = twodec(ezpp_acc_pp(ez)); | ||||
|  | ||||
|   printf("AR%g OD%g ", ar, od); | ||||
|  | ||||
|   if (ezpp_mode(ez) == MODE_STD) { | ||||
|     printf("CS%g ", cs); | ||||
|   } | ||||
|  | ||||
|   printf("HP%g\n", hp); | ||||
|   printf("300 hitwindow: %g ms\n", ezpp_odms(ez)); | ||||
|  | ||||
|   printf("%d circles, %d sliders, %d spinners\n", | ||||
|     ezpp_ncircles(ez), ezpp_nsliders(ez), ezpp_nspinners(ez)); | ||||
|  | ||||
|   if (ezpp_mode(ez) == MODE_STD) { | ||||
|     printf("%g stars (%g aim, %g speed)\n", stars, aim_stars, speed_stars); | ||||
|     printf("\nspeed strain: "); | ||||
|     asciiplt(getspeed, ezpp_nobjects(ez), ez); | ||||
|     printf("  aim strain: "); | ||||
|     asciiplt(getaim, ezpp_nobjects(ez), ez); | ||||
|   } else { | ||||
|     printf("%g stars\n", ezpp_stars(ez)); | ||||
|   } | ||||
|  | ||||
|   printf("\n"); | ||||
|  | ||||
|   if (mods_str) { | ||||
|     printf("+%s ", mods_str); | ||||
|   } | ||||
|  | ||||
|   printf("%d/%dx ", ezpp_combo(ez), ezpp_max_combo(ez)); | ||||
|   printf("%g%%\n", accuracy_percent); | ||||
|   printf("%g pp (", pp); | ||||
|  | ||||
|   if (ezpp_mode(ez) == MODE_STD) { | ||||
|     printf("%g aim, ", aim_pp); | ||||
|   } | ||||
|  | ||||
|   printf("%g speed, ", speed_pp); | ||||
|   printf("%g acc)\n\n", acc_pp); | ||||
| } | ||||
|  | ||||
| /* json output --------------------------------------------------------- */ | ||||
|  | ||||
| void print_escaped_json_string_ex(char* str, int quotes) { | ||||
|   char* chars_to_escape = "\\\""; | ||||
|   char* p; | ||||
|   if (quotes) { | ||||
|     putchar('"'); | ||||
|   } | ||||
|   for (; *str; ++str) { | ||||
|     /* escape all characters in chars_to_escape */ | ||||
|     for (p = chars_to_escape; *p; ++p) { | ||||
|       if (*p == *str) { | ||||
|         putchar('\\'); | ||||
|       } | ||||
|     } | ||||
|     putchar(*str); | ||||
|   } | ||||
|   if (quotes) { | ||||
|     putchar('"'); | ||||
|   } | ||||
| } | ||||
|  | ||||
| #define print_escaped_json_string(x) \ | ||||
|   print_escaped_json_string_ex(x, 1) | ||||
|  | ||||
| /* https://www.doc.ic.ac.uk/%7Eeedwards/compsys/float/nan.html */ | ||||
|  | ||||
| static int is_inf(float b) { | ||||
|   int* p = (int*)&b; | ||||
|   return *p == 0x7F800000 || *p == 0xFF800000; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * json is mentally challenged and can't handle inf and nan so | ||||
|  * we're gonna be mathematically incorrect | ||||
|  */ | ||||
| void fix_json_flt(float* v) { | ||||
|   if (is_inf(*v)) { | ||||
|     *v = -1; | ||||
|   } else if (is_nan(*v)) { | ||||
|     *v = 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| output_sig(output_json) { | ||||
|   float pp, aim_pp, speed_pp, acc_pp, stars, aim_stars, speed_stars; | ||||
|   printf("{\"oppai_version\":\"%s\",", oppai_version_str()); | ||||
|  | ||||
|   if (result < 0) { | ||||
|     printf("\"code\":%d,", result); | ||||
|     printf("\"errstr\":"); | ||||
|     print_escaped_json_string(errstr(result)); | ||||
|     printf("}"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   pp = ezpp_pp(ez); | ||||
|   aim_pp = ezpp_aim_pp(ez); | ||||
|   speed_pp = ezpp_speed_pp(ez); | ||||
|   acc_pp = ezpp_acc_pp(ez); | ||||
|   stars = ezpp_stars(ez); | ||||
|   aim_stars = ezpp_aim_stars(ez); | ||||
|   speed_stars = ezpp_speed_stars(ez); | ||||
|   fix_json_flt(&pp); | ||||
|   fix_json_flt(&aim_pp); | ||||
|   fix_json_flt(&speed_pp); | ||||
|   fix_json_flt(&acc_pp); | ||||
|   fix_json_flt(&stars); | ||||
|   fix_json_flt(&aim_stars); | ||||
|   fix_json_flt(&speed_stars); | ||||
|  | ||||
|   printf("\"code\":200,\"errstr\":\"no error\","); | ||||
|  | ||||
|   printf("\"artist\":"); | ||||
|   print_escaped_json_string(ezpp_artist(ez)); | ||||
|  | ||||
|   if (strcmp(ezpp_artist(ez), ezpp_artist_unicode(ez))) { | ||||
|     printf(",\"artist_unicode\":"); | ||||
|     print_escaped_json_string(ezpp_artist_unicode(ez)); | ||||
|   } | ||||
|  | ||||
|   printf(",\"title\":"); | ||||
|   print_escaped_json_string(ezpp_title(ez)); | ||||
|  | ||||
|   if (strcmp(ezpp_title(ez), ezpp_title_unicode(ez))) { | ||||
|     printf(",\"title_unicode\":"); | ||||
|     print_escaped_json_string(ezpp_title_unicode(ez)); | ||||
|   } | ||||
|  | ||||
|   printf(",\"creator\":"); | ||||
|   print_escaped_json_string(ezpp_creator(ez)); | ||||
|  | ||||
|   printf(",\"version\":"); | ||||
|   print_escaped_json_string(ezpp_version(ez)); | ||||
|  | ||||
|   printf(","); | ||||
|  | ||||
|   if (!mods_str) { | ||||
|     mods_str = ""; | ||||
|   } | ||||
|  | ||||
|   printf( | ||||
|     "\"mods_str\":\"%s\",\"mods\":%d," | ||||
|     "\"od\":%g,\"ar\":%g,\"cs\":%g,\"hp\":%g," | ||||
|     "\"combo\":%d,\"max_combo\":%d," | ||||
|     "\"num_circles\":%d,\"num_sliders\":%d," | ||||
|     "\"num_spinners\":%d,\"misses\":%d," | ||||
|     "\"score_version\":%d,\"stars\":%.17g," | ||||
|     "\"speed_stars\":%.17g,\"aim_stars\":%.17g," | ||||
|     "\"aim_pp\":%.17g,\"speed_pp\":%.17g,\"acc_pp\":%.17g," | ||||
|     "\"pp\":%.17g}", | ||||
|     mods_str, ezpp_mods(ez), ezpp_od(ez), ezpp_ar(ez), | ||||
|     ezpp_cs(ez), ezpp_hp(ez), ezpp_combo(ez), | ||||
|     ezpp_max_combo(ez), ezpp_ncircles(ez), ezpp_nsliders(ez), | ||||
|     ezpp_nspinners(ez), ezpp_nmiss(ez), ezpp_score_version(ez), | ||||
|     ezpp_stars(ez), ezpp_speed_stars(ez), ezpp_aim_stars(ez), | ||||
|     ezpp_aim_pp(ez), ezpp_speed_pp(ez), ezpp_acc_pp(ez), ezpp_pp(ez) | ||||
|   ); | ||||
| } | ||||
|  | ||||
| /* csv output ---------------------------------------------------------- */ | ||||
|  | ||||
| void print_escaped_csv_string(char* str) { | ||||
|   char* chars_to_escape = "\\;"; | ||||
|   char* p; | ||||
|   for (; *str; ++str) { | ||||
|     /* escape all characters in chars_to_escape */ | ||||
|     for (p = chars_to_escape; *p; ++p) { | ||||
|       if (*p == *str) { | ||||
|         putchar('\\'); | ||||
|       } | ||||
|     } | ||||
|     putchar(*str); | ||||
|   } | ||||
| } | ||||
|  | ||||
| output_sig(output_csv) { | ||||
|   printf("oppai_version;%s\n", oppai_version_str()); | ||||
|  | ||||
|   if (result < 0) { | ||||
|     printf("code;%d\nerrstr;", result); | ||||
|     print_escaped_csv_string(errstr(result)); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   printf("code;200\nerrstr;no error\n"); | ||||
|  | ||||
|   printf("artist;"); | ||||
|   print_escaped_csv_string(ezpp_artist(ez)); | ||||
|   puts(""); | ||||
|  | ||||
|   if (strcmp(ezpp_artist(ez), ezpp_artist_unicode(ez))) { | ||||
|     printf("artist_unicode;"); | ||||
|     print_escaped_csv_string(ezpp_artist_unicode(ez)); | ||||
|     puts(""); | ||||
|   } | ||||
|  | ||||
|   printf("title;"); | ||||
|   print_escaped_csv_string(ezpp_title(ez)); | ||||
|   puts(""); | ||||
|  | ||||
|   if (strcmp(ezpp_title(ez), ezpp_title_unicode(ez))) { | ||||
|     printf("title_unicode;"); | ||||
|     print_escaped_csv_string(ezpp_title_unicode(ez)); | ||||
|     puts(""); | ||||
|   } | ||||
|  | ||||
|   printf("version;"); | ||||
|   print_escaped_csv_string(ezpp_version(ez)); | ||||
|   puts(""); | ||||
|  | ||||
|   printf("creator;"); | ||||
|   print_escaped_csv_string(ezpp_creator(ez)); | ||||
|   puts(""); | ||||
|  | ||||
|   if (!mods_str) { | ||||
|     mods_str = ""; | ||||
|   } | ||||
|  | ||||
|   printf( | ||||
|     "mods_str;%s\nmods;%d\nod;%g\nar;%g\ncs;%g\nhp;%g\n" | ||||
|     "combo;%d\nmax_combo;%d\nnum_circles;%d\n" | ||||
|     "num_sliders;%d\nnum_spinners;%d\nmisses;%d\n" | ||||
|     "score_version;%d\nstars;%.17g\nspeed_stars;%.17g\n" | ||||
|     "aim_stars;%.17g\naim_pp;%.17g\nspeed_pp;%.17g\nacc_pp;%.17g\npp;%.17g", | ||||
|     mods_str, ezpp_mods(ez), ezpp_od(ez), ezpp_ar(ez), | ||||
|     ezpp_cs(ez), ezpp_hp(ez), ezpp_combo(ez), | ||||
|     ezpp_max_combo(ez), ezpp_ncircles(ez), ezpp_nsliders(ez), | ||||
|     ezpp_nspinners(ez), ezpp_nmiss(ez), ezpp_score_version(ez), | ||||
|     ezpp_stars(ez), ezpp_speed_stars(ez), ezpp_aim_stars(ez), | ||||
|     ezpp_aim_pp(ez), ezpp_speed_pp(ez), ezpp_acc_pp(ez), ezpp_pp(ez) | ||||
|   ); | ||||
| } | ||||
|  | ||||
| /* binary output ------------------------------------------------------- */ | ||||
|  | ||||
| void write1(int v) { | ||||
|   char buf = (char)(v & 0xFF); | ||||
|   fwrite(&buf, 1, 1, stdout); | ||||
| } | ||||
|  | ||||
| void write2(int v) { | ||||
|   char buf[2]; | ||||
|   buf[0] = (char)(v & 0xFF); | ||||
|   buf[1] = (char)(v >> 8); | ||||
|   fwrite(buf, 1, 2, stdout); | ||||
| } | ||||
|  | ||||
| void write4(int v) { | ||||
|   char buf[4]; | ||||
|   buf[0] = (char)(v & 0xFF); | ||||
|   buf[1] = (char)((v >> 8) & 0xFF); | ||||
|   buf[2] = (char)((v >> 16) & 0xFF); | ||||
|   buf[3] = (char)((v >> 24) & 0xFF); | ||||
|   fwrite(buf, 1, 4, stdout); | ||||
| } | ||||
|  | ||||
| void write_flt(float f) { | ||||
|   int* p = (int*)&f; | ||||
|   write4(*p); | ||||
| } | ||||
|  | ||||
| void write_str(char* str) { | ||||
|   int len = al_min(0xFFFF, (int)strlen(str)); | ||||
|   write2(len); | ||||
|   printf("%s", str); | ||||
|   write1(0); | ||||
| } | ||||
|  | ||||
| output_sig(output_binary) { | ||||
|   int major, minor, patch; | ||||
|   (void)mods_str; | ||||
|  | ||||
|   if (!freopen(0, "wb", stdout)) { | ||||
|     perror("freopen"); | ||||
|     exit(1); | ||||
|   } | ||||
|  | ||||
|   printf("binoppai"); | ||||
|   oppai_version(&major, &minor, &patch); | ||||
|   write1(major); | ||||
|   write1(minor); | ||||
|   write1(patch); | ||||
|   write4(result); | ||||
|  | ||||
|   if (result < 0) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   /* TODO: use varargs to group calls of the same func */ | ||||
|   write_str(ezpp_artist(ez)); | ||||
|   write_str(ezpp_artist_unicode(ez)); | ||||
|   write_str(ezpp_title(ez)); | ||||
|   write_str(ezpp_title_unicode(ez)); | ||||
|   write_str(ezpp_version(ez)); | ||||
|   write_str(ezpp_creator(ez)); | ||||
|   write4(ezpp_mods(ez)); | ||||
|   write_flt(ezpp_od(ez)); | ||||
|   write_flt(ezpp_ar(ez)); | ||||
|   write_flt(ezpp_cs(ez)); | ||||
|   write_flt(ezpp_hp(ez)); | ||||
|   write4(ezpp_combo(ez)); | ||||
|   write4(ezpp_max_combo(ez)); | ||||
|   write2(ezpp_ncircles(ez)); | ||||
|   write2(ezpp_nsliders(ez)); | ||||
|   write2(ezpp_nspinners(ez)); | ||||
|   write4(ezpp_score_version(ez)); | ||||
|   write_flt(ezpp_stars(ez)); | ||||
|   write_flt(ezpp_speed_stars(ez)); | ||||
|   write_flt(ezpp_aim_stars(ez)); | ||||
|   write2(0); /* legacy (nsingles) */ | ||||
|   write2(0); /* legacy (nsigles_threshold) */ | ||||
|   write_flt(ezpp_aim_pp(ez)); | ||||
|   write_flt(ezpp_speed_pp(ez)); | ||||
|   write_flt(ezpp_acc_pp(ez)); | ||||
|   write_flt(ezpp_pp(ez)); | ||||
| } | ||||
|  | ||||
| /* gnuplot output ------------------------------------------------------ */ | ||||
|  | ||||
| #define gnuplot_string(x) print_escaped_json_string_ex(x, 0) | ||||
|  | ||||
| void gnuplot_strains(ezpp_t ez, int type) { | ||||
|   int i; | ||||
|   for (i = 0; i < ezpp_nobjects(ez); ++i) { | ||||
|     printf("%.17g %.17g\n", ezpp_time_at(ez, i), | ||||
|       ezpp_strain_at(ez, i, type)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| output_sig(output_gnuplot) { | ||||
|   if (result < 0 || ezpp_mode(ez) != MODE_STD) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   puts("set encoding utf8;"); | ||||
|  | ||||
|   printf("set title \""); | ||||
|   gnuplot_string(ezpp_artist(ez)); | ||||
|   printf(" - "); | ||||
|   gnuplot_string(ezpp_title(ez)); | ||||
|  | ||||
|   if (strcmp(ezpp_artist(ez), ezpp_artist_unicode(ez)) || | ||||
|     strcmp(ezpp_title(ez), ezpp_title_unicode(ez))) | ||||
|   { | ||||
|     printf("("); | ||||
|     gnuplot_string(ezpp_artist_unicode(ez)); | ||||
|     printf(" - "); | ||||
|     gnuplot_string(ezpp_title_unicode(ez)); | ||||
|     printf(")"); | ||||
|   } | ||||
|  | ||||
|   printf(" ["); | ||||
|   gnuplot_string(ezpp_version(ez)); | ||||
|   printf("] mapped by "); | ||||
|   gnuplot_string(ezpp_creator(ez)); | ||||
|   if (mods_str) printf(" +%s", mods_str); | ||||
|   puts("\";"); | ||||
|  | ||||
|   puts( | ||||
|     "set xlabel 'time (ms)';" | ||||
|     "set ylabel 'strain';" | ||||
|     "set multiplot layout 2,1 rowsfirst;" | ||||
|     "plot '-' with lines lc 1 title 'speed'" | ||||
|   ); | ||||
|   gnuplot_strains(ez, DIFF_SPEED); | ||||
|   puts("e"); | ||||
|   puts("unset title;"); | ||||
|   puts("plot '-' with lines lc 2 title 'aim'"); | ||||
|   gnuplot_strains(ez, DIFF_AIM); | ||||
| } | ||||
|  | ||||
| /* ------------------------------------------------------------- */ | ||||
|  | ||||
| #define CODE_DESC "the code and errstr fields " \ | ||||
|   "should be checked for errors. a negative value for code " \ | ||||
|   "indicates an error" | ||||
|  | ||||
| typedef struct output_module { | ||||
|   char* name; | ||||
|   fnoutput* func; | ||||
|   char* description[4]; | ||||
|   /* null terminated array of strings because of c90 literal limits */ | ||||
| } output_module_t; | ||||
|  | ||||
| output_module_t modules[] = { | ||||
|   { "null", output_null, { "no output", 0 } }, | ||||
|   { "text", output_text, { "plain text", 0 } }, | ||||
|   { | ||||
|     "json", output_json, | ||||
|     { "a single utf-8 json object.\n" CODE_DESC, 0 } | ||||
|   }, | ||||
|   { | ||||
|     "csv", output_csv, | ||||
|     { "fieldname;value\n" | ||||
|     "one value per line. ';' characters in strings will be "  | ||||
|     "escaped to \"\\;\". utf-8.\n" CODE_DESC, 0 } | ||||
|   }, | ||||
|   { | ||||
|     "binary", | ||||
|     output_binary, | ||||
|     { "binary stream of values, encoded in little endian.\n" | ||||
|     "negative code values indicate an error, which matches " | ||||
|     "the error codes defined in oppai.c\n" | ||||
|     "for an example on how to read this in C, check out " | ||||
|     "examples/binary.c in oppai-ng's source\n" | ||||
|     "\n" | ||||
|     "floats and floats are represented using whatever " | ||||
|     "convention the host machine and compiler use. unless you " | ||||
|     "are on a really exotic machine it shouldn't matter\n" | ||||
|     "\n" | ||||
|     "strings (str) are encoded as a 2-byte integer indicating " | ||||
|     "the length in bytes, followed by the string bytes and ", | ||||
|     "a null (zero) terminating byte\n" | ||||
|     "\n" | ||||
|     "binoppai (8-byte magic), " | ||||
|     "int8 oppai_ver_major, int8 oppai_ver_minor, " | ||||
|     "int8 oppai_ver_patch, int error_code, " | ||||
|     "str artist, str artist_utf8, str title, str title_utf8, " | ||||
|     "str version, str creator, " | ||||
|     "int mods_bitmask, float od, float ar, float cs, " | ||||
|     "float hp, int combo, int max_combo, " | ||||
|     "int16 ncircles, int16 nsliders, int16 nspinner, " | ||||
|     "int score_version, float total_stars, ", | ||||
|     "float speed_stars, float aim_stars, int16 nsingles, " | ||||
|     "int16 nsingles_threshold, float aim_pp, " | ||||
|     "float speed_pp, float acc_pp, float pp", | ||||
|     0 } | ||||
|   }, | ||||
|   { "gnuplot", output_gnuplot, { "gnuplot .gp script", 0 } }, | ||||
| }; | ||||
|  | ||||
| output_module_t* output_by_name(char* name) { | ||||
|   int i; | ||||
|   for (i = 0; i < array_len(modules); ++i) { | ||||
|     if (!strcmp(modules[i].name, name)) { | ||||
|       return &modules[i]; | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int cmpsuffix(char* str, char* suffix) { | ||||
|   int sufflen = (int)al_min(strlen(str), strlen(suffix)); | ||||
|   return strcmp(str + strlen(str) - sufflen, suffix); | ||||
| } | ||||
|  | ||||
| char lowercase(char c) { | ||||
|   if (c >= 'A' && c <= 'Z') { | ||||
|     return c + ('a' - 'A'); | ||||
|   } | ||||
|   return c; | ||||
| } | ||||
|  | ||||
| char uppercase(char c) { | ||||
|   if (c >= 'a' && c <= 'z') { | ||||
|     return c - ('a' - 'A'); | ||||
|   } | ||||
|   return c; | ||||
| } | ||||
|  | ||||
| int strcmp_nc(char* a, char* b) { | ||||
|   for (;; ++a, ++b) { | ||||
|     char la = lowercase(*a); | ||||
|     char lb = lowercase(*b); | ||||
|     if (la > lb) { | ||||
|       return 1; | ||||
|     } | ||||
|     else if (la < lb) { | ||||
|       return -1; | ||||
|     } | ||||
|     if (!*a || *b) { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* TODO: split main into smaller funcs for readability? */ | ||||
| int main(int argc, char* argv[]) { | ||||
|   int i; | ||||
|   int result; | ||||
|   ezpp_t ez = ezpp_new(); | ||||
|   output_module_t* m; | ||||
|   char* output_name = "text"; | ||||
|   char* mods_str = 0; | ||||
|   int mods = MODS_NOMOD; | ||||
|   float tmpf, speed_stars = 0, aim_stars = 0, accuracy_percent = 0; | ||||
|   int tmpi, n100 = 0, n50 = 0; | ||||
|  | ||||
|   /* parse arguments ------------------------------------------------- */ | ||||
|   me = argv[0]; | ||||
|  | ||||
|   if (argc < 2) { | ||||
|     usage(); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   if (*argv[1] == '-' && strlen(argv[1]) > 1) { | ||||
|     char* a = argv[1] + 1; | ||||
|     if (!strcmp_nc(a, "version") || !strcmp_nc(a, "v")) { | ||||
|       puts(oppai_version_str()); | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (i = 2; i < argc; ++i) { | ||||
|     char* a = argv[i]; | ||||
|     char* p; | ||||
|     int iswhite = 1; | ||||
|  | ||||
|     for (p = a; *p; ++p) { | ||||
|       if (!isspace(*p)) { | ||||
|         iswhite = 0; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (iswhite) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     for (p = a; *p; ++p) { | ||||
|       *p = lowercase(*p); | ||||
|     } | ||||
|  | ||||
|     if (*a == '-' && a[1] == 'o') { | ||||
|       output_name = a + 2; | ||||
|  | ||||
|       if (!strcmp(output_name, "?")) { | ||||
|         int j; | ||||
|         int nmodules = sizeof(modules) / sizeof(modules[0]); | ||||
|         for (j = 0; j < nmodules; ++j) { | ||||
|           char** d = modules[j].description; | ||||
|           puts(modules[j].name); | ||||
|           for (; *d; ++d) { | ||||
|             printf("%s", *d); | ||||
|           } | ||||
|           puts("\n-"); | ||||
|         } | ||||
|         return 0; | ||||
|       } | ||||
|  | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "%") && sscanf(a, "%f", &accuracy_percent) == 1) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "x100") && sscanf(a, "%d", &n100) == 1) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "x50") && sscanf(a, "%d", &n50) == 1) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "speed") && sscanf(a, "%f", &speed_stars) == 1) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "aim") && sscanf(a, "%f", &aim_stars) == 1) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "xm") || !cmpsuffix(a, "xmiss") || | ||||
|       !cmpsuffix(a, "m")) | ||||
|     { | ||||
|       if (sscanf(a, "%d", &tmpi) == 1) { | ||||
|         ezpp_set_nmiss(ez, tmpi); | ||||
|         continue; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (!cmpsuffix(a, "x") && sscanf(a, "%d", &tmpi) == 1) { | ||||
|       ezpp_set_combo(ez, tmpi); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "scorev%d", &tmpi)) { | ||||
|       ezpp_set_score_version(ez, tmpi); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "ar%f", &tmpf)) { | ||||
|       ezpp_set_base_ar(ez, tmpf); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "od%f", &tmpf)) { | ||||
|       ezpp_set_base_od(ez, tmpf); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "cs%f", &tmpf)) { | ||||
|       ezpp_set_base_cs(ez, tmpf); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "-m%d", &tmpi) == 1) { | ||||
|       ezpp_set_mode_override(ez, tmpi); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (sscanf(a, "-end%d", &tmpi) == 1) { | ||||
|       ezpp_set_end(ez, tmpi); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!strcmp(a, "-taiko")) { | ||||
|       ezpp_set_mode_override(ez, MODE_TAIKO); | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     if (!strcmp(a, "-touch")) { | ||||
|       mods |= MODS_TOUCH_DEVICE; | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     /* this should be last because it uppercase's the string */ | ||||
|     if (*a == '+') { | ||||
|       mods_str = a + 1; | ||||
|       for (p = mods_str; *p; ++p) { | ||||
|         *p = uppercase(*p); | ||||
|       } | ||||
|  | ||||
|       #define m(mod) \ | ||||
|         if (!strncmp(p, #mod, strlen(#mod))) { \ | ||||
|           mods |= MODS_##mod; \ | ||||
|           p += strlen(#mod); \ | ||||
|           continue; \ | ||||
|         } | ||||
|  | ||||
|       for (p = mods_str; *p;) { | ||||
|         m(NF) m(EZ) m(TD) m(HD) m(HR) m(SD) m(DT) m(RX) m(HT) m(NC) m(FL) | ||||
|         m(AT) m(SO) m(AP) m(PF) m(NOMOD) | ||||
|         ++p; | ||||
|       } | ||||
|  | ||||
|       #undef m | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     info(">%s\n", a); | ||||
|     result = ERR_SYNTAX; | ||||
|     goto output; | ||||
|   } | ||||
|  | ||||
|   if (accuracy_percent) { | ||||
|     ezpp_set_accuracy_percent(ez, accuracy_percent); | ||||
|   } else { | ||||
|     ezpp_set_accuracy(ez, n100, n50); | ||||
|   } | ||||
|   ezpp_set_mods(ez, mods); | ||||
|   ezpp_set_speed_stars(ez, speed_stars); | ||||
|   ezpp_set_aim_stars(ez, aim_stars); | ||||
|   result = ezpp(ez, argv[1]); | ||||
|  | ||||
| output: | ||||
|   m = output_by_name(output_name); | ||||
|   if (!m) { | ||||
|     info("output module '%s' does not exist. check 'oppai - -o?'\n", | ||||
|       output_name); | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   m->func(result, ez, mods_str); | ||||
|   ezpp_free(ez); /* just so valgrind stops crying */ | ||||
|   return result < 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										16
									
								
								package
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								package
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir=$(dirname $0) | ||||
| dir=$(readlink -f $dir) | ||||
| prevdir=$(pwd) | ||||
| cd $dir | ||||
| #git pull origin master || exit $? | ||||
| for prefix in i386/ ""; do | ||||
|   container="${prefix}oppai-ng:ubuntu" | ||||
|   docker build -t "$container" \ | ||||
|     --build-arg PREFIX="$prefix" . || exit $? | ||||
|   docker run --rm -v $dir:/tmp \ | ||||
|     -e arch=$(echo ${prefix:-x86_64} | tr -d /) \ | ||||
|     "$container" || exit $? | ||||
| done | ||||
| cd $prevdir | ||||
							
								
								
									
										49
									
								
								release
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								release
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir=$(dirname $0) | ||||
|  | ||||
| olddir=$(pwd) | ||||
| cd $dir | ||||
|  | ||||
| echo"" | ||||
| echo "compiling and stripping" | ||||
| CC=musl-gcc ./build -static -no-pie || exit $? | ||||
| CC=gcc ./libbuild || exit $? | ||||
|  | ||||
| echo"" | ||||
| echo "packaging" | ||||
| folder="oppai-$(./oppai -version)-" | ||||
| folder="${folder}$(gcc -dumpmachine)" | ||||
|  | ||||
| mkdir -p "$folder" || exit $? | ||||
| mv ./oppai $folder/oppai || exit $? | ||||
| mv ./liboppai.so $folder/liboppai.so || exit $? | ||||
| git archive HEAD --prefix=src/ -o "$folder"/src.tar || | ||||
|   exit $? | ||||
| cd "$folder" || exit $? | ||||
| tar xf src.tar || exit $? | ||||
| cd .. || exit $? | ||||
|  | ||||
| rm "$folder".tar.xz | ||||
| tar -cvJf "$folder".tar.xz \ | ||||
|   "$folder"/oppai \ | ||||
|   "$folder"/liboppai.so \ | ||||
|   "$folder"/src \ | ||||
|   || exit $? | ||||
|  | ||||
| echo "" | ||||
| file "$folder".tar.xz | ||||
| tar tf "$folder".tar.xz | ||||
|  | ||||
| echo "" | ||||
| file "$folder"/oppai | ||||
| readelf --dynamic "$folder"/oppai | ||||
| ldd "$folder"/oppai | ||||
|  | ||||
| echo "" | ||||
| file "$folder"/liboppai.so | ||||
| ldd "$folder"/liboppai.so | ||||
|  | ||||
| rm -rf "$folder" | ||||
| cd $olddir | ||||
|  | ||||
							
								
								
									
										59
									
								
								release.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								release.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| # you must allow script execution by running | ||||
| # 'Set-ExecutionPolicy RemoteSigned' in an admin powershell | ||||
| # this requires vcvars to be already set (see vcvarsall17.ps1) | ||||
| # 7zip is also required (choco install 7zip and add it to path) | ||||
|  | ||||
| $dir = Split-Path -Parent $MyInvocation.MyCommand.Definition | ||||
|  | ||||
| Push-Location "$dir" | ||||
| git pull origin master -q | ||||
|  | ||||
| function Write-Header { | ||||
|   param ([string]$Text) | ||||
|   Write-Host $Text -Foreground Yellow -Background Black | ||||
| } | ||||
|  | ||||
| function Header { | ||||
|   param ([string]$Title) | ||||
|   Write-Header "" | ||||
|   Write-Header "##########################################################" | ||||
|   Write-Header "> $Title" | ||||
| } | ||||
|  | ||||
| cmd /c "build.bat"; if (-not $?) { exit $LastExitCode } | ||||
| cmd /c "libbuild.bat"; if (-not $?) { exit $LastExitCode } | ||||
| Header "Packaging" | ||||
| $folder = "oppai-" + $(.\oppai.exe -version) + "-windows-" | ||||
| $clout = & cl 2>&1 | %{ "$_" } | ||||
| "$clout" -match "(Microsoft.*for )([a-z0-9\-_]+)" | Out-Null | ||||
| if (-not $?) { | ||||
|   exit $LastExitCode | ||||
| } | ||||
| $folder = $folder + $Matches[2] | ||||
| mkdir $folder; if (-not $?) { exit $LastExitCode } | ||||
| Copy-Item oppai.exe $folder; if (-not $?) { exit $LastExitCode } | ||||
| Copy-Item oppai.dll $folder; if (-not $?) { exit $LastExitCode } | ||||
| Copy-Item oppai.lib $folder; if (-not $?) { exit $LastExitCode } | ||||
| git archive HEAD --prefix=src\ -o $folder\src.zip | ||||
| if (-not $?) { | ||||
|   exit $LastExitCode | ||||
| } | ||||
| Set-Location $folder; if (-not $?) { exit $LastExitCode } | ||||
| &7z x src.zip; if (-not $?) { exit $LastExitCode } | ||||
| Set-Location ..; if (-not $?) { exit $LastExitCode } | ||||
|  | ||||
| if (Test-Path "$folder.zip") { | ||||
|   Remove-Item "$folder.zip" | ||||
| } | ||||
|  | ||||
| &7z a "$folder.zip" $folder\oppai.exe $folder\oppai.dll $folder\oppai.lib ` | ||||
|   $folder\src | ||||
| if (-not $?) { | ||||
|   exit $LastExitCode | ||||
| } | ||||
|  | ||||
| Header "Result:" | ||||
| &7z l "$folder.zip" | ||||
|  | ||||
| Remove-Item $folder -Force -Recurse | ||||
| Pop-Location | ||||
							
								
								
									
										17
									
								
								swig/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								swig/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| these are maintainer instructions, check the readme's in the binding | ||||
| directories for user guides | ||||
|  | ||||
| # requirements | ||||
| * swig | ||||
| * docker | ||||
| * twine (pip) | ||||
|  | ||||
| # building all bindings | ||||
| ```sh | ||||
| ./build.sh | ||||
| ``` | ||||
|  | ||||
| # publishing all bindings | ||||
| ```sh | ||||
| PUBLISH=1 ./build.sh | ||||
| ``` | ||||
							
								
								
									
										19
									
								
								swig/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								swig/build.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| runall() { | ||||
|   for d in ./*/; do | ||||
|     [ "$d" = "." ] && continue | ||||
|     cd "$d" | ||||
|     ./build.sh || return $? | ||||
|     [ ! -z $PUBLISH ] && ./publish.sh | ||||
|     cd .. | ||||
|   done | ||||
| } | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| olddir="$(pwd)" | ||||
| cd "$dir" | ||||
| runall | ||||
| res=$? | ||||
| cd "$olddir" | ||||
| exit $res | ||||
							
								
								
									
										11
									
								
								swig/oppai.i
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								swig/oppai.i
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| %module oppai | ||||
| %feature("autodoc", "3"); | ||||
| %apply int *OUTPUT {int*} | ||||
| %begin{ | ||||
| #define SWIG_PYTHON_2_UNICODE | ||||
| } | ||||
| %{ | ||||
| #define OPPAI_IMPLEMENTATION | ||||
| #include "oppai.c" | ||||
| %} | ||||
| #include "oppai.c" | ||||
							
								
								
									
										42
									
								
								swig/python/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								swig/python/README.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| osu! pp and difficulty calculator. automatically generated C bindings for | ||||
| https://github.com/Francesco149/oppai-ng | ||||
|  | ||||
| usage | ||||
| =========== | ||||
| .. code-block:: sh | ||||
|  | ||||
|     pip install oppai | ||||
|  | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     #!/usr/bin/env python | ||||
|  | ||||
|     import sys | ||||
|     from oppai import * | ||||
|  | ||||
|     ez = ezpp_new() | ||||
|     ezpp(ez, sys.argv[1]) | ||||
|     print("%g pp" % ezpp_pp(ez)) | ||||
|     ezpp_free(ez) | ||||
|  | ||||
|  | ||||
| .. code-block:: sh | ||||
|  | ||||
|     ./example.py /path/to/file.osu | ||||
|  | ||||
| .. code-block:: sh | ||||
|  | ||||
|     python -c 'help("oppai")' | ||||
|  | ||||
| for a list of functions, or just read the top of oppai.c for better doc | ||||
|  | ||||
|  | ||||
| limitations | ||||
| =========== | ||||
| for some reason, python3 doesn't provide a persisting pointer to strings | ||||
| you pass to c code even if you aren't doing anything with them, so if you | ||||
| want to reuse the handle at all you have to use ezpp_dup and ezpp_data_dup, | ||||
| which create a copy of the strings you pass in. this is inefficient so | ||||
| it's recommended to use autocalc mode and only call ezpp_dup or | ||||
| ezpp_data_dup when you're actually changing map | ||||
							
								
								
									
										10
									
								
								swig/python/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								swig/python/build.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| rm -rf ./dist | ||||
| cp ../../oppai.c . | ||||
| cp ../oppai.i . | ||||
| swig -python -includeall oppai.i || exit | ||||
| for img in quay.io/pypa/manylinux2010_x86_64 quay.io/pypa/manylinux2010_i686; do | ||||
|   docker run --user 1000:1000 --rm -v $(pwd):/io -w /io $img \ | ||||
|     ./build_wheels.sh || exit | ||||
| done | ||||
							
								
								
									
										15
									
								
								swig/python/build_wheels.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								swig/python/build_wheels.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #!/bin/sh | ||||
| # this is meant to be used from docker | ||||
|  | ||||
| for pybin in /opt/python/*/bin | ||||
| do | ||||
|   rm *.so | ||||
|   "$pybin/pip" wheel . -w dist/ || exit | ||||
| done | ||||
|  | ||||
| "$pybin/python" ./setup.py sdist || exit | ||||
|  | ||||
| for w in dist/*linux_*.whl; do | ||||
|   auditwheel repair "$w" -w dist/ || exit | ||||
| done | ||||
| rm dist/*linux_*.whl | ||||
							
								
								
									
										9
									
								
								swig/python/examples/basic.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								swig/python/examples/basic.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
| from oppai import * | ||||
|  | ||||
| ez = ezpp_new() | ||||
| ezpp(ez, sys.argv[1]) | ||||
| print("%g pp" % ezpp_pp(ez)) | ||||
| ezpp_free(ez) | ||||
							
								
								
									
										16
									
								
								swig/python/examples/reuse.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								swig/python/examples/reuse.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
| from oppai import * | ||||
|  | ||||
| ez = ezpp_new() | ||||
| ezpp_set_autocalc(ez, 1) | ||||
| for osufile in sys.argv[1:]: | ||||
|   ezpp_dup(ez, osufile) | ||||
|   print("%s - %s [%s]" % (ezpp_artist(ez), ezpp_title(ez), ezpp_version(ez))) | ||||
|   print("%g stars" % ezpp_stars(ez)) | ||||
|   for acc in range(95, 101): | ||||
|     ezpp_set_accuracy_percent(ez, acc) | ||||
|     print("%g%% -> %g pp" % (acc, ezpp_pp(ez))) | ||||
|   print("") | ||||
| ezpp_free(ez) | ||||
							
								
								
									
										38
									
								
								swig/python/examples/reuse_mem.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								swig/python/examples/reuse_mem.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
| from oppai import * | ||||
|  | ||||
| if sys.version_info[0] < 3: | ||||
|   # hack to force utf-8 on py < 3 | ||||
|   reload(sys) | ||||
|   sys.setdefaultencoding("utf-8") | ||||
|  | ||||
| def mods_str(mods): | ||||
|   mods_str = "+" | ||||
|   if mods == 0: | ||||
|     mods_str += "nomod" | ||||
|   else: | ||||
|     if mods & MODS_HD: mods_str += "hd" | ||||
|     if mods & MODS_DT: mods_str += "dt" | ||||
|     if mods & MODS_HR: mods_str += "hr" | ||||
|   return mods_str | ||||
|  | ||||
| ez = ezpp_new() | ||||
| ezpp_set_autocalc(ez, 1) | ||||
| for osufile in sys.argv[1:]: | ||||
|   # by providing the map in memory we can speed up subsequent re-parses | ||||
|   f = open(osufile, 'r') | ||||
|   data = f.read() | ||||
|   f.close() | ||||
|   ezpp_data_dup(ez, data, len(data.encode('utf-8'))) | ||||
|   print("%s - %s [%s]" % (ezpp_artist(ez), ezpp_title(ez), ezpp_version(ez))) | ||||
|   print("%g stars" % ezpp_stars(ez)) | ||||
|   for mods in [ 0, MODS_HR, MODS_HD | MODS_HR, MODS_DT, MODS_HD | MODS_DT ]: | ||||
|     print(mods_str(mods)) | ||||
|     ezpp_set_mods(ez, mods) | ||||
|     for acc in range(95, 101): | ||||
|       ezpp_set_accuracy_percent(ez, acc) | ||||
|       print("%g%% -> %g pp" % (acc, ezpp_pp(ez))) | ||||
|   print("") | ||||
| ezpp_free(ez) | ||||
							
								
								
									
										14
									
								
								swig/python/examples/timing.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								swig/python/examples/timing.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
| from oppai import * | ||||
|  | ||||
| # prints timing points (just a test for this interface) | ||||
| ez = ezpp_new() | ||||
| ezpp(ez, sys.argv[1]) | ||||
| for i in range(ezpp_ntiming_points(ez)): | ||||
|   time = ezpp_timing_time(ez, i) | ||||
|   ms_per_beat = ezpp_timing_ms_per_beat(ez, i) | ||||
|   change = ezpp_timing_change(ez, i) | ||||
|   print("%f | %f beats per ms | change: %d" % (time, ms_per_beat, change)) | ||||
| ezpp_free(ez) | ||||
							
								
								
									
										3
									
								
								swig/python/publish.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								swig/python/publish.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| twine upload dist/* | ||||
							
								
								
									
										25
									
								
								swig/python/python.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								swig/python/python.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| environment: | ||||
|   TWINE_USERNAME: lolisamurai | ||||
|   TWINE_PASSWORD: | ||||
|     secure: DTyX4L2loxFxlsbPYAwuga0DyOlGiOnJyEwi/j08gba0NyNx21TvRFMHpITIqcfg | ||||
| cache: | ||||
| - C:\ProgramData\chocolatey\bin | ||||
| - C:\ProgramData\chocolatey\lib | ||||
| - C:\Users\appveyor\AppData\Local\pip\Cache | ||||
| install: | ||||
| - IF NOT EXIST C:\ProgramData\chocolatey\bin\swig.exe choco install swig --version 3.0.12 --yes --limit-output | ||||
| - python -m pip install twine | ||||
| - python -m pip install cibuildwheel==0.10.1 | ||||
| build_script: | ||||
| - cd swig/python | ||||
| - copy ..\..\oppai.c . | ||||
| - copy ..\oppai.i . | ||||
| - swig -python -includeall oppai.i | ||||
| - cibuildwheel --output-dir wheelhouse | ||||
| - ps: >- | ||||
|     if ($env:APPVEYOR_REPO_TAG -eq "true") { | ||||
|       Invoke-Expression "python -m twine upload --skip-existing wheelhouse/*.whl" | ||||
|     } | ||||
| artifacts: | ||||
|   - path: "swig\\python\\wheelhouse\\*.whl" | ||||
|     name: wheels | ||||
							
								
								
									
										2
									
								
								swig/python/setup.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								swig/python/setup.cfg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| [build_ext] | ||||
| swig-opts=-includeall | ||||
							
								
								
									
										58
									
								
								swig/python/setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								swig/python/setup.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| import os | ||||
| import sys | ||||
|  | ||||
| def parse_version_str(): | ||||
|   import re | ||||
|   version_re = re.compile('^#define OPPAI_VERSION_(MAJOR|MINOR|PATCH)') | ||||
|   version = [] | ||||
|   with open('oppai.c', 'r') as f: | ||||
|     for line in f: | ||||
|       if version_re.match(line): | ||||
|         version.append(str(int(line.split(' ')[2]))) | ||||
|   return '.'.join(version) | ||||
|  | ||||
| try: | ||||
|     from setuptools import setup, Extension | ||||
| except ImportError: | ||||
|     from distutils.core import setup, Extension | ||||
|  | ||||
| try: | ||||
|   from oppai import oppai_version_str | ||||
| except Exception: | ||||
|   def oppai_version_str(): | ||||
|     try: | ||||
|       return parse_version_str() | ||||
|     except Exception: | ||||
|       return "INVALID" | ||||
|  | ||||
| oppai_classifiers = [ | ||||
|     "Programming Language :: Python :: 2", | ||||
|     "Programming Language :: Python :: 3", | ||||
|     "Intended Audience :: Developers", | ||||
|     "License :: Public Domain", | ||||
|     "Topic :: Software Development :: Libraries", | ||||
|     "Topic :: Utilities", | ||||
| ] | ||||
|  | ||||
| f = open("README.rst", "r") | ||||
| oppai_readme = f.read() | ||||
| f.close() | ||||
|  | ||||
| oppai_sources=['oppai.i'] | ||||
| if os.system('swig') != 0: | ||||
|   oppai_sources=['oppai_wrap.c', 'oppai.c'] | ||||
|  | ||||
| setup( | ||||
|     name="oppai", | ||||
|     version=oppai_version_str(), | ||||
|     author="Franc[e]sco", | ||||
|     author_email="lolisamurai@tfwno.gf", | ||||
|     url="https://github.com/Francesco149/oppai-ng", | ||||
|     ext_modules=[Extension('_oppai', oppai_sources)], | ||||
|     py_modules=["oppai"], | ||||
|     description="osu! pp and difficulty calculator, C bindings", | ||||
|     long_description=oppai_readme, | ||||
|     license="Unlicense", | ||||
|     classifiers=oppai_classifiers, | ||||
|     keywords="osu! osu" | ||||
| ) | ||||
							
								
								
									
										497
									
								
								test.osu
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										497
									
								
								test.osu
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,497 @@ | ||||
| osu file format v14 | ||||
|  | ||||
| [General] | ||||
| AudioFilename: audio.mp3 | ||||
| AudioLeadIn: 0 | ||||
| PreviewTime: 64748 | ||||
| Countdown: 0 | ||||
| SampleSet: Soft | ||||
| StackLeniency: 0.7 | ||||
| Mode: 0 | ||||
| LetterboxInBreaks: 0 | ||||
| WidescreenStoryboard: 0 | ||||
|  | ||||
| [Editor] | ||||
| Bookmarks: 2807,8454,19748,31042,42336,53630,64924,76218 | ||||
| DistanceSpacing: 0.7 | ||||
| BeatDivisor: 4 | ||||
| GridSize: 16 | ||||
| TimelineZoom: 2.1 | ||||
|  | ||||
| [Metadata] | ||||
| Title:The Weekend Whip (TV Size) ~Speed Up Ver.~ | ||||
| TitleUnicode:The Weekend Whip (TV Size) ~Speed Up Ver.~ | ||||
| Artist:The Fold | ||||
| ArtistUnicode:The Fold | ||||
| Creator:Julaaaan | ||||
| Version:Spin! | ||||
| Source: | ||||
| Tags: | ||||
| BeatmapID:0 | ||||
| BeatmapSetID:-1 | ||||
|  | ||||
| [Difficulty] | ||||
| HPDrainRate:5.1 | ||||
| CircleSize:3.8 | ||||
| OverallDifficulty:9.1 | ||||
| ApproachRate:9.4 | ||||
| SliderMultiplier:1.9 | ||||
| SliderTickRate:1 | ||||
|  | ||||
| [Events] | ||||
| //Background and Video events | ||||
| 0,0,"spin.jpg",0,0 | ||||
| //Break Periods | ||||
| //Storyboard Layer 0 (Background) | ||||
| //Storyboard Layer 1 (Fail) | ||||
| //Storyboard Layer 2 (Pass) | ||||
| //Storyboard Layer 3 (Foreground) | ||||
| //Storyboard Layer 4 (Overlay) | ||||
| //Storyboard Sound Samples | ||||
|  | ||||
| [TimingPoints] | ||||
| 2807,352.941176470588,4,2,0,100,1,0 | ||||
| 2807,-200,4,2,0,40,0,0 | ||||
| 5630,-142.857142857143,4,2,0,50,0,0 | ||||
| 7042,-125,4,2,0,60,0,0 | ||||
| 8101,-90.9090909090909,4,2,0,70,0,0 | ||||
| 8365,-90.9090909090909,4,2,0,5,0,0 | ||||
| 8454,-111.111111111111,4,2,0,80,0,0 | ||||
| 19748,-111.111111111111,4,2,0,70,0,0 | ||||
| 30689,-90.9090909090909,4,2,0,70,0,0 | ||||
| 30954,-90.9090909090909,4,2,0,5,0,0 | ||||
| 31042,-111.111111111111,4,2,0,90,0,1 | ||||
| 31748,-111.111111111111,4,2,0,70,0,0 | ||||
| 32454,-111.111111111111,4,2,0,90,0,1 | ||||
| 33159,-111.111111111111,4,2,0,70,0,0 | ||||
| 33777,-111.111111111111,4,2,0,5,0,0 | ||||
| 33865,-111.111111111111,4,2,0,80,0,0 | ||||
| 36689,-111.111111111111,4,2,0,90,0,1 | ||||
| 37395,-111.111111111111,4,2,0,70,0,0 | ||||
| 38101,-111.111111111111,4,2,0,90,0,1 | ||||
| 38806,-111.111111111111,4,2,0,70,0,0 | ||||
| 39424,-111.111111111111,4,2,0,5,0,0 | ||||
| 39512,-111.111111111111,4,2,0,80,0,0 | ||||
| 42336,-111.111111111111,4,2,0,80,0,0 | ||||
| 53630,-111.111111111111,4,2,0,90,0,1 | ||||
| 54336,-111.111111111111,4,2,0,70,0,0 | ||||
| 55042,-111.111111111111,4,2,0,90,0,1 | ||||
| 55748,-111.111111111111,4,2,0,70,0,0 | ||||
| 56365,-111.111111111111,4,2,0,5,0,0 | ||||
| 56454,-111.111111111111,4,2,0,80,0,0 | ||||
| 59277,-111.111111111111,4,2,0,90,0,1 | ||||
| 59983,-111.111111111111,4,2,0,70,0,0 | ||||
| 60689,-111.111111111111,4,2,0,90,0,1 | ||||
| 61395,-111.111111111111,4,2,0,70,0,0 | ||||
| 62012,-111.111111111111,4,2,0,5,0,0 | ||||
| 62101,-111.111111111111,4,2,0,80,0,0 | ||||
| 64924,-90.9090909090909,4,2,0,80,0,1 | ||||
| 86101,-90.9090909090909,4,2,0,70,0,1 | ||||
| 93159,-166.666666666667,4,2,0,40,0,0 | ||||
| 94571,-125,4,2,0,60,0,0 | ||||
| 96512,-125,4,2,0,30,0,0 | ||||
|  | ||||
|  | ||||
| [Colours] | ||||
| Combo1 : 153,153,153 | ||||
| Combo2 : 237,27,36 | ||||
| Combo3 : 0,90,213 | ||||
| Combo4 : 198,250,255 | ||||
| Combo5 : 177,101,101 | ||||
| Combo6 : 24,170,97 | ||||
| Combo7 : 17,170,254 | ||||
| Combo8 : 255,255,255 | ||||
|  | ||||
| [HitObjects] | ||||
| 105,119,2807,6,0,P|103:164|108:185,1,47.5 | ||||
| 167,137,3159,2,0,P|173:177|181:194,1,47.5 | ||||
| 327,122,3512,6,0,P|326:94|319:70,1,47.5 | ||||
| 379,100,3865,2,0,P|375:74|366:53,1,47.5 | ||||
| 416,230,4218,6,0,P|399:260|379:273,1,47.5 | ||||
| 430,287,4571,2,0,P|411:310|386:322,1,47.5 | ||||
| 178,244,4924,6,0,P|157:213|136:204,1,47.5 | ||||
| 123,255,5277,2,0,P|91:240|67:241,1,47.5 | ||||
| 225,353,5630,6,0,P|265:338|285:313,1,66.4999979705811 | ||||
| 277,183,5983,2,0,P|236:209|221:235,1,66.4999979705811 | ||||
| 394,271,6336,6,0,P|424:249|439:204,1,66.4999979705811 | ||||
| 365,74,6689,2,0,P|336:109|324:142,1,66.4999979705811 | ||||
| 303,271,7042,5,0,0:0:0:0: | ||||
| 209,53,7218,1,0,0:0:0:0: | ||||
| 191,228,7395,1,0,0:0:0:0: | ||||
| 310,44,7571,2,0,P|318:73|319:92,1,38 | ||||
| 332,239,7748,5,0,0:0:0:0: | ||||
| 317,216,7836,1,0,0:0:0:0: | ||||
| 295,200,7924,1,0,0:0:0:0: | ||||
| 270,189,8012,1,0,0:0:0:0: | ||||
| 243,188,8101,2,0,B|178:182|131:221|131:221|155:232|169:220,1,156.750004783631 | ||||
| 221,223,8454,5,0,0:0:0:0: | ||||
| 116,54,8630,1,0,0:0:0:0: | ||||
| 93,271,8806,1,0,0:0:0:0: | ||||
| 235,88,8983,1,0,0:0:0:0: | ||||
| 292,304,9159,5,0,0:0:0:0: | ||||
| 134,154,9336,1,0,0:0:0:0: | ||||
| 371,184,9512,1,0,0:0:0:0: | ||||
| 170,332,9689,1,0,0:0:0:0: | ||||
| 262,146,9865,6,0,P|287:220|280:254,1,85.4999973907472 | ||||
| 222,358,10218,2,0,P|183:315|172:274,1,85.4999973907472 | ||||
| 175,134,10571,6,0,P|119:125|83:133,1,85.4999973907472 | ||||
| 1,273,10924,2,0,P|58:288|99:280,1,85.4999973907472 | ||||
| 195,188,11277,6,0,P|228:235|241:288,1,85.4999973907472 | ||||
| 165,368,11630,1,0,0:0:0:0: | ||||
| 288,162,11806,1,0,0:0:0:0: | ||||
| 288,338,11983,1,0,0:0:0:0: | ||||
| 105,141,12159,1,0,0:0:0:0: | ||||
| 47,326,12336,1,0,0:0:0:0: | ||||
| 226,192,12512,1,0,0:0:0:0: | ||||
| 165,368,12689,6,0,B|164:345|174:332|174:332|168:314|168:314|185:293|175:266,1,85.4999973907472 | ||||
| 237,142,13042,1,0,0:0:0:0: | ||||
| 301,348,13218,1,0,0:0:0:0: | ||||
| 325,121,13395,5,0,0:0:0:0: | ||||
| 205,316,13571,1,0,0:0:0:0: | ||||
| 192,72,13748,5,0,0:0:0:0: | ||||
| 396,289,13924,1,0,0:0:0:0: | ||||
| 372,57,14101,6,0,P|347:101|343:152,1,85.4999973907472 | ||||
| 352,238,14454,1,0,0:0:0:0: | ||||
| 330,168,14630,1,0,0:0:0:0: | ||||
| 215,239,14806,1,0,0:0:0:0: | ||||
| 281,218,14983,1,0,0:0:0:0: | ||||
| 201,114,15159,1,0,0:0:0:0: | ||||
| 149,240,15336,1,0,0:0:0:0: | ||||
| 276,139,15512,6,0,P|316:126|374:154,1,85.4999973907472 | ||||
| 440,202,15865,1,0,0:0:0:0: | ||||
| 373,256,16042,1,0,0:0:0:0: | ||||
| 290,233,16218,1,0,0:0:0:0: | ||||
| 263,314,16395,1,0,0:0:0:0: | ||||
| 199,149,16571,1,0,0:0:0:0: | ||||
| 159,332,16748,6,0,B|76:279|78:177,1,170.999994781494 | ||||
| 107,79,17277,1,0,0:0:0:0: | ||||
| 148,154,17454,1,0,0:0:0:0: | ||||
| 216,102,17630,1,0,0:0:0:0: | ||||
| 215,248,17806,1,0,0:0:0:0: | ||||
| 79,136,17983,1,0,0:0:0:0: | ||||
| 271,162,18159,1,0,0:0:0:0: | ||||
| 90,252,18336,6,0,P|136:212|159:176,1,85.4999973907472 | ||||
| 187,75,18689,1,0,0:0:0:0: | ||||
| 255,286,18865,1,0,0:0:0:0: | ||||
| 303,72,19042,5,0,0:0:0:0: | ||||
| 149,285,19218,1,0,0:0:0:0: | ||||
| 196,28,19395,5,0,0:0:0:0: | ||||
| 337,257,19571,1,0,0:0:0:0: | ||||
| 381,25,19748,38,0,P|340:70|328:122,1,85.4999973907472 | ||||
| 199,74,20101,1,0,0:0:0:0: | ||||
| 132,126,20277,1,0,0:0:0:0: | ||||
| 46,130,20454,2,0,P|40:207|57:242,1,85.4999973907472 | ||||
| 114,337,20806,1,0,0:0:0:0: | ||||
| 184,171,20983,1,0,0:0:0:0: | ||||
| 286,310,21159,5,0,0:0:0:0: | ||||
| 320,142,21336,2,0,P|348:192|347:230,1,85.4999973907472 | ||||
| 206,76,21689,2,0,P|166:122|153:159,1,85.4999973907472 | ||||
| 441,103,22042,2,0,P|399:60|347:45,2,85.4999973907472 | ||||
| 401,282,22571,6,0,P|350:253|325:210,1,85.4999973907472 | ||||
| 265,120,22924,1,0,0:0:0:0: | ||||
| 217,191,23101,1,0,0:0:0:0: | ||||
| 144,146,23277,1,0,0:0:0:0: | ||||
| 114,311,23454,1,0,0:0:0:0: | ||||
| 26,116,23630,1,0,0:0:0:0: | ||||
| 185,266,23806,6,0,P|167:213|176:171,1,85.4999973907472 | ||||
| 265,74,24159,1,0,0:0:0:0: | ||||
| 296,225,24336,1,0,0:0:0:0: | ||||
| 368,126,24512,1,0,0:0:0:0: | ||||
| 391,290,24689,1,0,0:0:0:0: | ||||
| 241,150,24865,1,0,0:0:0:0: | ||||
| 208,270,25042,1,0,0:0:0:0: | ||||
| 324,92,25218,1,0,0:0:0:0: | ||||
| 326,288,25395,6,0,P|288:263|241:245,1,85.4999973907472 | ||||
| 80,194,25748,1,0,0:0:0:0: | ||||
| 145,139,25924,1,0,0:0:0:0: | ||||
| 228,159,26101,2,0,P|290:126|330:89,1,85.4999973907472 | ||||
| 358,24,26454,1,0,0:0:0:0: | ||||
| 458,212,26630,1,0,0:0:0:0: | ||||
| 482,72,26806,5,0,0:0:0:0: | ||||
| 342,238,26983,1,0,0:0:0:0: | ||||
| 387,33,27159,1,0,0:0:0:0: | ||||
| 436,237,27336,2,0,P|438:288|422:340,1,85.4999973907472 | ||||
| 241,264,27689,2,0,P|249:208|279:166,1,85.4999973907472 | ||||
| 346,110,28042,1,0,0:0:0:0: | ||||
| 198,106,28218,6,0,P|155:131|121:164,1,85.4999973907472 | ||||
| 62,270,28571,1,0,0:0:0:0: | ||||
| 84,72,28748,1,0,0:0:0:0: | ||||
| 159,231,28924,2,0,P|199:261|235:272,1,85.4999973907472 | ||||
| 301,182,29277,2,0,P|353:186|387:195,1,85.4999973907472 | ||||
| 470,328,29630,6,0,P|409:340|369:323,1,85.4999973907472 | ||||
| 248,212,29983,1,0,0:0:0:0: | ||||
| 288,364,30159,1,0,0:0:0:0: | ||||
| 371,164,30336,1,0,0:0:0:0: | ||||
| 194,321,30512,1,0,0:0:0:0: | ||||
| 151,121,30689,2,0,B|182:110|216:124|216:124|248:113|248:113|275:127|306:115,1,156.750004783631 | ||||
| 352,66,31042,5,0,0:0:0:0: | ||||
| 281,339,31218,1,0,0:0:0:0: | ||||
| 184,75,31395,1,0,0:0:0:0: | ||||
| 168,81,31748,1,0,0:0:0:0: | ||||
| 163,97,32101,1,0,0:0:0:0: | ||||
| 147,103,32454,5,0,0:0:0:0: | ||||
| 412,0,32630,1,0,0:0:0:0: | ||||
| 324,280,32806,1,0,0:0:0:0: | ||||
| 309,289,33159,1,0,0:0:0:0: | ||||
| 291,288,33512,2,0,P|226:267|145:293,1,128.249996086121 | ||||
| 145,298,33865,5,0,0:0:0:0: | ||||
| 203,140,34042,1,0,0:0:0:0: | ||||
| 228,306,34218,2,0,P|254:268|288:240,1,85.4999973907472 | ||||
| 394,178,34571,1,0,0:0:0:0: | ||||
| 357,310,34748,1,0,0:0:0:0: | ||||
| 305,159,34924,1,0,0:0:0:0: | ||||
| 436,264,35101,6,0,P|460:216|469:169,1,85.4999973907472 | ||||
| 444,42,35454,2,0,P|383:79|359:113,1,85.4999973907472 | ||||
| 386,209,35806,2,0,P|326:223|288:210,1,85.4999973907472 | ||||
| 223,151,36159,2,0,P|195:208|201:252,2,85.4999973907472 | ||||
| 362,101,36689,5,0,0:0:0:0: | ||||
| 470,337,36865,1,0,0:0:0:0: | ||||
| 265,214,37042,1,0,0:0:0:0: | ||||
| 258,229,37395,1,0,0:0:0:0: | ||||
| 261,245,37748,1,0,0:0:0:0: | ||||
| 250,258,38101,5,0,0:0:0:0: | ||||
| 145,27,38277,1,0,0:0:0:0: | ||||
| 97,277,38454,1,0,0:0:0:0: | ||||
| 113,273,38806,1,0,0:0:0:0: | ||||
| 122,287,39159,2,0,B|190:331|190:331|250:317,1,128.249996086121 | ||||
| 274,328,39512,5,0,0:0:0:0: | ||||
| 241,174,39689,1,0,0:0:0:0: | ||||
| 379,266,39865,2,0,P|324:239|278:234,1,85.4999973907472 | ||||
| 170,277,40218,1,0,0:0:0:0: | ||||
| 290,112,40395,1,0,0:0:0:0: | ||||
| 300,283,40571,1,0,0:0:0:0: | ||||
| 138,185,40748,1,0,0:0:0:0: | ||||
| 114,351,40924,6,0,P|172:313|192:277,1,85.4999973907472 | ||||
| 221,169,41277,5,0,0:0:0:0: | ||||
| 306,341,41454,1,0,0:0:0:0: | ||||
| 358,123,41630,5,0,0:0:0:0: | ||||
| 208,299,41806,1,0,0:0:0:0: | ||||
| 203,71,41983,5,0,0:0:0:0: | ||||
| 376,258,42159,1,0,0:0:0:0: | ||||
| 366,49,42336,86,0,P|321:89|306:145,1,85.4999973907472 | ||||
| 275,252,42689,1,0,0:0:0:0: | ||||
| 231,178,42865,1,0,0:0:0:0: | ||||
| 279,107,43042,1,0,0:0:0:0: | ||||
| 140,177,43218,1,0,0:0:0:0: | ||||
| 160,93,43395,1,0,0:0:0:0: | ||||
| 216,262,43571,1,0,0:0:0:0: | ||||
| 278,75,43748,6,0,P|329:82|361:129,1,85.4999973907472 | ||||
| 359,268,44101,1,0,0:0:0:0: | ||||
| 259,168,44277,2,0,P|194:152|156:162,1,85.4999973907472 | ||||
| 76,247,44630,2,0,P|121:273|172:268,2,85.4999973907472 | ||||
| 121,48,45159,6,0,P|127:111|116:139,1,85.4999973907472 | ||||
| 15,242,45512,1,0,0:0:0:0: | ||||
| 194,133,45689,1,0,0:0:0:0: | ||||
| 127,307,45865,2,0,P|120:254|131:209,1,85.4999973907472 | ||||
| 179,91,46218,1,0,0:0:0:0: | ||||
| 195,264,46395,6,0,B|247:283|290:251|264:255|311:223|365:228,1,170.999994781494 | ||||
| 405,275,46924,1,0,0:0:0:0: | ||||
| 300,91,47101,1,0,0:0:0:0: | ||||
| 246,253,47277,5,0,0:0:0:0: | ||||
| 387,54,47454,1,0,0:0:0:0: | ||||
| 330,325,47630,5,0,0:0:0:0: | ||||
| 213,70,47806,1,0,0:0:0:0: | ||||
| 156,337,47983,102,0,P|171:292|206:267,1,85.4999973907472 | ||||
| 383,231,48336,1,0,0:0:0:0: | ||||
| 303,199,48512,1,0,0:0:0:0: | ||||
| 259,125,48689,2,0,P|210:106|146:110,1,85.4999973907472 | ||||
| 54,164,49042,1,0,0:0:0:0: | ||||
| 169,10,49218,1,0,0:0:0:0: | ||||
| 180,224,49395,5,0,0:0:0:0: | ||||
| 93,70,49571,1,0,0:0:0:0: | ||||
| 62,264,49748,1,0,0:0:0:0: | ||||
| 171,112,49924,2,0,P|221:94|261:101,1,85.4999973907472 | ||||
| 397,169,50277,2,0,P|351:208|314:222,1,85.4999973907472 | ||||
| 228,178,50630,1,0,0:0:0:0: | ||||
| 118,238,50806,6,0,P|188:266|215:290,1,85.4999973907472 | ||||
| 288,352,51159,1,0,0:0:0:0: | ||||
| 345,178,51336,1,0,0:0:0:0: | ||||
| 401,328,51512,1,0,0:0:0:0: | ||||
| 258,212,51689,2,0,P|249:247|211:295,1,85.4999973907472 | ||||
| 155,198,52042,6,0,P|182:130|286:109,1,170.999994781494 | ||||
| 436,210,52571,2,0,P|454:171|457:129,1,85.4999973907472 | ||||
| 403,63,52924,1,0,0:0:0:0: | ||||
| 320,39,53101,1,0,0:0:0:0: | ||||
| 244,78,53277,2,0,P|190:85|133:65,1,85.4999973907472 | ||||
| 40,35,53630,5,0,0:0:0:0: | ||||
| 34,255,53806,1,0,0:0:0:0: | ||||
| 184,27,53983,1,0,0:0:0:0: | ||||
| 194,40,54336,1,0,0:0:0:0: | ||||
| 211,41,54689,1,0,0:0:0:0: | ||||
| 217,56,55042,5,0,0:0:0:0: | ||||
| 470,0,55218,1,0,0:0:0:0: | ||||
| 273,174,55395,1,0,0:0:0:0: | ||||
| 265,189,55748,1,0,0:0:0:0: | ||||
| 272,204,56101,2,0,B|301:229|341:220|331:210|371:206|410:239,1,128.249996086121 | ||||
| 399,254,56454,5,0,0:0:0:0: | ||||
| 386,80,56630,1,0,0:0:0:0: | ||||
| 494,202,56806,2,0,P|439:179|408:176,1,85.4999973907472 | ||||
| 262,226,57159,1,0,0:0:0:0: | ||||
| 314,83,57336,1,0,0:0:0:0: | ||||
| 350,279,57512,1,0,0:0:0:0: | ||||
| 183,160,57689,6,0,P|179:217|202:253,1,85.4999973907472 | ||||
| 295,305,58042,2,0,P|245:330|191:334,1,85.4999973907472 | ||||
| 44,279,58395,2,0,P|75:243|115:223,1,85.4999973907472 | ||||
| 282,198,58748,2,0,P|291:142|278:97,2,85.4999973907472 | ||||
| 175,304,59277,5,0,0:0:0:0: | ||||
| 425,233,59454,1,0,0:0:0:0: | ||||
| 151,144,59630,1,0,0:0:0:0: | ||||
| 165,134,59983,1,0,0:0:0:0: | ||||
| 171,118,60336,1,0,0:0:0:0: | ||||
| 187,115,60689,5,0,0:0:0:0: | ||||
| 290,317,60865,1,0,0:0:0:0: | ||||
| 343,75,61042,1,0,0:0:0:0: | ||||
| 339,91,61395,1,0,0:0:0:0: | ||||
| 347,105,61748,2,0,B|361:148|361:148|348:188|348:188|359:229,1,128.249996086121 | ||||
| 391,249,62101,5,0,0:0:0:0: | ||||
| 239,192,62277,1,0,0:0:0:0: | ||||
| 325,338,62454,2,0,P|305:287|304:252,1,85.4999973907472 | ||||
| 334,102,62806,5,0,0:0:0:0: | ||||
| 199,265,62983,1,0,0:0:0:0: | ||||
| 199,76,63159,2,0,P|213:129|248:166,1,85.4999973907472 | ||||
| 381,172,63512,6,0,P|380:197|375:218,1,42.7499986953736 | ||||
| 276,282,63689,1,0,0:0:0:0: | ||||
| 259,262,63777,1,0,0:0:0:0: | ||||
| 237,248,63865,6,0,P|205:228|189:224,1,42.7499986953736 | ||||
| 76,258,64042,2,0,P|102:283|127:295,1,42.7499986953736 | ||||
| 186,172,64218,5,0,0:0:0:0: | ||||
| 214,162,64306,1,0,0:0:0:0: | ||||
| 244,163,64395,2,0,P|279:173|301:189,1,42.7499986953736 | ||||
| 352,304,64571,5,0,0:0:0:0: | ||||
| 352,304,64924,70,0,P|371:247|366:200,1,104.500003189087 | ||||
| 242,58,65277,2,0,B|191:108|191:108|150:111,1,104.500003189087 | ||||
| 0,168,65630,5,0,0:0:0:0: | ||||
| 167,347,65806,1,0,0:0:0:0: | ||||
| 140,123,65983,2,0,P|167:197|150:266,1,104.500003189087 | ||||
| 60,313,66336,5,0,0:0:0:0: | ||||
| 299,232,66512,1,0,0:0:0:0: | ||||
| 61,204,66689,1,0,0:0:0:0: | ||||
| 281,341,66865,2,0,P|221:324|179:289,1,104.500003189087 | ||||
| 181,76,67218,2,0,P|232:139|235:176,1,104.500003189087 | ||||
| 130,343,67571,1,0,0:0:0:0: | ||||
| 120,163,67748,6,0,P|167:214|212:226,1,104.500003189087 | ||||
| 431,213,68101,2,0,B|381:153|381:153|348:151,1,104.500003189087 | ||||
| 216,278,68454,5,0,0:0:0:0: | ||||
| 314,61,68630,1,0,0:0:0:0: | ||||
| 335,278,68806,5,0,0:0:0:0: | ||||
| 204,75,68983,1,0,0:0:0:0: | ||||
| 148,343,69159,6,0,P|199:308|244:298,1,104.500003189087 | ||||
| 407,173,69512,2,0,P|338:180|296:161,1,104.500003189087 | ||||
| 108,41,69865,5,0,0:0:0:0: | ||||
| 373,96,70042,1,0,0:0:0:0: | ||||
| 114,135,70218,1,0,0:0:0:0: | ||||
| 358,17,70395,6,0,B|300:35|271:87|296:80|269:131|190:144,1,209.000006378174 | ||||
| 48,125,70924,5,0,0:0:0:0: | ||||
| 299,262,71101,1,0,0:0:0:0: | ||||
| 108,223,71277,5,0,0:0:0:0: | ||||
| 404,127,71454,1,0,0:0:0:0: | ||||
| 220,123,71630,5,0,0:0:0:0: | ||||
| 465,270,71806,1,0,0:0:0:0: | ||||
| 245,262,71983,6,0,P|291:237|321:171,1,104.500003189087 | ||||
| 336,66,72336,5,0,0:0:0:0: | ||||
| 246,338,72512,1,0,0:0:0:0: | ||||
| 222,32,72689,5,0,0:0:0:0: | ||||
| 354,282,72865,1,0,0:0:0:0: | ||||
| 367,0,73042,5,0,0:0:0:0: | ||||
| 227,238,73218,1,0,0:0:0:0: | ||||
| 430,92,73395,6,0,P|390:107|340:171,1,104.500003189087 | ||||
| 305,329,73748,1,0,0:0:0:0: | ||||
| 244,75,73924,2,0,P|226:142|237:194,1,104.500003189087 | ||||
| 414,280,74277,5,0,0:0:0:0: | ||||
| 140,279,74454,1,0,0:0:0:0: | ||||
| 368,165,74630,1,0,0:0:0:0: | ||||
| 264,350,74806,6,0,P|263:307|239:243,1,104.500003189087 | ||||
| 172,157,75159,1,0,0:0:0:0: | ||||
| 107,338,75336,1,0,0:0:0:0: | ||||
| 90,115,75512,5,0,0:0:0:0: | ||||
| 193,367,75689,1,0,0:0:0:0: | ||||
| 254,81,75865,5,0,0:0:0:0: | ||||
| 43,295,76042,1,0,0:0:0:0: | ||||
| 93,29,76218,54,0,P|135:86|146:153,1,104.500003189087 | ||||
| 148,296,76571,2,0,B|231:303|231:303|292:270,1,104.500003189087 | ||||
| 299,138,76924,5,0,0:0:0:0: | ||||
| 377,353,77101,1,0,0:0:0:0: | ||||
| 454,132,77277,2,0,P|436:200|383:250,1,104.500003189087 | ||||
| 190,289,77630,5,0,0:0:0:0: | ||||
| 357,148,77806,1,0,0:0:0:0: | ||||
| 302,349,77983,1,0,0:0:0:0: | ||||
| 172,155,78159,2,0,P|222:198|255:249,1,104.500003189087 | ||||
| 186,383,78512,2,0,P|129:339|107:293,1,104.500003189087 | ||||
| 91,106,78865,1,0,0:0:0:0: | ||||
| 209,248,79042,6,0,P|266:220|295:171,1,104.500003189087 | ||||
| 408,70,79395,2,0,B|453:142|453:142|452:174,1,104.500003189087 | ||||
| 382,335,79748,5,0,0:0:0:0: | ||||
| 283,127,79924,1,0,0:0:0:0: | ||||
| 270,335,80101,5,0,0:0:0:0: | ||||
| 392,141,80277,1,0,0:0:0:0: | ||||
| 202,262,80454,6,0,P|150:225|139:181,1,104.500003189087 | ||||
| 154,31,80806,2,0,B|81:56|81:56|64:83,1,104.500003189087 | ||||
| 49,271,81159,5,0,0:0:0:0: | ||||
| 249,109,81336,1,0,0:0:0:0: | ||||
| 128,338,81512,1,0,0:0:0:0: | ||||
| 154,88,81689,6,0,B|142:168|195:244|195:244|203:198,1,209.000006378174 | ||||
| 244,100,82218,5,0,0:0:0:0: | ||||
| 350,317,82395,1,0,0:0:0:0: | ||||
| 362,60,82571,5,0,0:0:0:0: | ||||
| 253,282,82748,1,0,0:0:0:0: | ||||
| 249,4,82924,5,0,0:0:0:0: | ||||
| 356,243,83101,1,0,0:0:0:0: | ||||
| 165,75,83277,6,0,P|203:119|257:137,1,104.500003189087 | ||||
| 439,130,83630,5,0,0:0:0:0: | ||||
| 173,252,83806,1,0,0:0:0:0: | ||||
| 398,263,83983,5,0,0:0:0:0: | ||||
| 103,135,84159,1,0,0:0:0:0: | ||||
| 334,140,84336,5,0,0:0:0:0: | ||||
| 54,232,84512,1,0,0:0:0:0: | ||||
| 198,59,84689,6,0,P|228:127|232:180,1,104.500003189087 | ||||
| 134,324,85042,1,0,0:0:0:0: | ||||
| 353,161,85218,2,0,P|332:237|287:275,1,104.500003189087 | ||||
| 89,201,85571,5,0,0:0:0:0: | ||||
| 321,339,85748,1,0,0:0:0:0: | ||||
| 53,335,85924,1,0,0:0:0:0: | ||||
| 318,246,86101,6,0,P|244:252|187:278,1,104.500003189087 | ||||
| 88,360,86454,1,0,0:0:0:0: | ||||
| 181,171,86630,1,0,0:0:0:0: | ||||
| 233,358,86806,6,0,P|176:322|146:283,1,104.500003189087 | ||||
| 206,115,87159,2,0,P|265:170|288:222,1,104.500003189087 | ||||
| 306,306,87512,69,0,0:0:0:0: | ||||
| 382,46,87689,1,0,0:0:0:0: | ||||
| 444,271,87865,5,0,0:0:0:0: | ||||
| 254,44,88042,1,0,0:0:0:0: | ||||
| 221,324,88218,5,0,0:0:0:0: | ||||
| 347,123,88395,1,0,0:0:0:0: | ||||
| 352,362,88571,5,0,0:0:0:0: | ||||
| 241,154,88748,1,0,0:0:0:0: | ||||
| 468,187,88924,5,0,0:0:0:0: | ||||
| 212,280,89101,1,0,0:0:0:0: | ||||
| 420,275,89277,5,0,0:0:0:0: | ||||
| 133,176,89454,1,0,0:0:0:0: | ||||
| 352,169,89630,5,0,0:0:0:0: | ||||
| 76,281,89806,1,0,0:0:0:0: | ||||
| 234,94,89983,1,0,0:0:0:0: | ||||
| 261,329,90159,22,0,B|273:255|273:255|247:204,1,104.500003189087 | ||||
| 154,133,90512,1,0,0:0:0:0: | ||||
| 138,296,90689,5,0,0:0:0:0: | ||||
| 287,98,90865,1,0,0:0:0:0: | ||||
| 295,297,91042,5,0,0:0:0:0: | ||||
| 163,63,91218,1,0,0:0:0:0: | ||||
| 141,238,91395,5,0,0:0:0:0: | ||||
| 293,3,91571,2,0,B|312:75|312:75|302:104,1,104.500003189087 | ||||
| 122,151,91924,1,0,0:0:0:0: | ||||
| 383,222,92101,5,0,0:0:0:0: | ||||
| 136,315,92277,1,0,0:0:0:0: | ||||
| 331,107,92454,5,0,0:0:0:0: | ||||
| 237,365,92630,1,0,0:0:0:0: | ||||
| 215,37,92806,5,0,0:0:0:0: | ||||
| 349,340,92983,1,0,0:0:0:0: | ||||
| 383,29,93159,22,0,P|380:74|372:98,1,56.9999982604981 | ||||
| 292,101,93512,2,0,P|295:67|307:46,1,56.9999982604981 | ||||
| 366,203,93865,6,0,P|354:255|337:279,1,56.9999982604981 | ||||
| 272,276,94218,2,0,P|277:225|292:197,1,56.9999982604981 | ||||
| 305,112,94571,6,0,P|259:98|213:104,2,76 | ||||
| 296,276,95101,5,0,0:0:0:0: | ||||
| 303,250,95189,1,0,0:0:0:0: | ||||
| 305,223,95277,5,0,0:0:0:0: | ||||
| 228,127,95454,1,0,0:0:0:0: | ||||
| 194,268,95630,5,0,0:0:0:0: | ||||
| 352,147,95806,6,0,B|258:136|196:208|252:196|174:276|74:253,1,304 | ||||
							
								
								
									
										8
									
								
								test/build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								test/build
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| . "$dir"/../cflags | ||||
|  | ||||
| $cc $cflags ${@:--DOPPAI_IMPLEMENTATION} \ | ||||
|   test.c $ldflags -o oppai_test | ||||
|  | ||||
							
								
								
									
										16
									
								
								test/build.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/build.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| @echo off | ||||
|  | ||||
| set flags="%*" | ||||
| IF "%1"=="" ( | ||||
|   set flags=-DOPPAI_IMPLEMENTATION | ||||
| ) | ||||
|  | ||||
| del oppai_test.exe >nul 2>&1 | ||||
| del test.obj >nul 2>&1 | ||||
| cl  -D_CRT_SECURE_NO_WARNINGS=1 ^ | ||||
|   -DNOMINMAX=1 ^ | ||||
|   -O2 -nologo -MT -Gm- -GR- -EHsc -W4 ^ | ||||
|   %flags% ^ | ||||
|   test.c ^ | ||||
|   -Feoppai_test.exe ^ | ||||
|   || EXIT /B 1 | ||||
							
								
								
									
										21
									
								
								test/download_suite
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								test/download_suite
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| if command -v realpath 2>&1 >/dev/null; then | ||||
|   wdir="$(realpath "$dir")" | ||||
| else | ||||
|   wdir="$dir" | ||||
| fi | ||||
| olddir="$(pwd)" | ||||
| cd "$wdir" || exit $? | ||||
|  | ||||
| url="$(cat ./suite_url)" | ||||
|  | ||||
| if [ $(find test_suite 2>/dev/null | tail -n +2 | wc -l) = "0" ]; then | ||||
|   curl -LO "$url" || exit $? | ||||
|   tar xf "$(basename $url)" || exit $? | ||||
| else | ||||
|   echo "using existing test_suite" | ||||
| fi | ||||
|  | ||||
| cd "$olddir" | ||||
							
								
								
									
										19
									
								
								test/download_suite.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/download_suite.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # you must allow script execution by running | ||||
| # 'Set-ExecutionPolicy RemoteSigned' in an admin powershell | ||||
| # 7zip is also required (choco install 7zip and add it to path) | ||||
|  | ||||
| $url = Get-Content .\suite_url -Raw | ||||
| $dir = Split-Path -Parent $MyInvocation.MyCommand.Definition | ||||
| Push-Location "$dir" | ||||
|  | ||||
| if ((Test-Path .\test_suite) -and (Get-ChildItem .\test_suite | Measure-Object).Count -gt 0) { | ||||
|   Write-Host "using existing test_suite" | ||||
| } else { | ||||
|   # my windows 7 install doesn't support Tls3 | ||||
|   [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | ||||
|   (New-Object System.Net.WebClient).DownloadFile($url, "$dir\test_suite.tar.gz") | ||||
|   &7z x .\test_suite.tar.gz | ||||
|   &7z x .\test_suite.tar | ||||
| } | ||||
|  | ||||
| Pop-Location | ||||
							
								
								
									
										79
									
								
								test/download_suite.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								test/download_suite.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| # very rough script that downloads unique maps from test_suite.json that | ||||
| # gensuite.py generates | ||||
|  | ||||
| import sys | ||||
| import json | ||||
|  | ||||
| try: | ||||
|     import httplib | ||||
| except ImportError: | ||||
|     import http.client as httplib | ||||
|  | ||||
| try: | ||||
|     import urllib | ||||
| except ImportError: | ||||
|     import urllib.parse as urllib | ||||
|  | ||||
| osu = httplib.HTTPSConnection('osu.ppy.sh') | ||||
|  | ||||
| def osu_get(path): | ||||
|     while True: | ||||
|         try: | ||||
|             osu.request('GET', path) | ||||
|             r = osu.getresponse() | ||||
|  | ||||
|             raw = bytes() | ||||
|  | ||||
|             while True: | ||||
|                 try: | ||||
|                     raw += r.read() | ||||
|                     break | ||||
|                 except httplib.IncompleteRead as e: | ||||
|                     raw += e.partial | ||||
|  | ||||
|             return raw | ||||
|  | ||||
|         except (httplib.HTTPException, ValueError) as e: | ||||
|             sys.stderr.write('%s\n' % (traceback.format_exc())) | ||||
|  | ||||
|             # prevents exceptions on next request if the | ||||
|             # response wasn't previously read due to errors | ||||
|             try: | ||||
|                 osu.getresponse().read() | ||||
|             except httplib.HTTPException: | ||||
|                 pass | ||||
|  | ||||
|             time.sleep(5) | ||||
|  | ||||
|  | ||||
| if len(sys.argv) != 2: | ||||
|     sys.stderr.write('usage: %s test_suite.json\n' % sys.argv[0]) | ||||
|     sys.exit(1) | ||||
|  | ||||
| with open(sys.argv[1], 'r') as f: | ||||
|     scores = json.loads(f.read()) | ||||
|  | ||||
| unique_maps = set([s['beatmap_id'] for m in [0, 1] for s in scores[m]]) | ||||
| i = 1 | ||||
|  | ||||
| for b in unique_maps: | ||||
|     sys.stderr.write( | ||||
|         "[%.02f%% - %d/%d] %s" % (i / float(len(unique_maps)) * 100, i, | ||||
|             len(unique_maps), b) | ||||
|     ) | ||||
|     i += 1 | ||||
|  | ||||
|     # TODO: tmp file and rename | ||||
|     try: | ||||
|         with open(b + '.osu', 'r') as f: | ||||
|             sys.stderr.write(' (already exists)\n') | ||||
|             continue | ||||
|     except FileNotFoundError: | ||||
|         pass | ||||
|  | ||||
|     sys.stderr.write('\n') | ||||
|  | ||||
|     with open(b + '.osu', 'wb') as f: | ||||
|         f.write(osu_get('/osu/' + b)) | ||||
							
								
								
									
										292
									
								
								test/gentest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								test/gentest.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,292 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import time | ||||
| import json | ||||
| import traceback | ||||
| import argparse | ||||
| import hashlib | ||||
|  | ||||
| if sys.version_info[0] < 3: | ||||
|   # hack to force utf-8 | ||||
|   reload(sys) | ||||
|   sys.setdefaultencoding('utf-8') | ||||
|  | ||||
| try: | ||||
|   import httplib | ||||
| except ImportError: | ||||
|   import http.client as httplib | ||||
|  | ||||
| try: | ||||
|   import urllib | ||||
| except ImportError: | ||||
|   import urllib.parse as urllib | ||||
|  | ||||
| # ------------------------------------------------------------------------- | ||||
|  | ||||
| parser = argparse.ArgumentParser( | ||||
|   description = ( | ||||
|     'generates the oppai test suite. outputs c++ code to ' + | ||||
|     'stdout and the json dump to a file.' | ||||
|   ) | ||||
| ) | ||||
|  | ||||
| parser.add_argument( | ||||
|   '-key', | ||||
|   default = None, | ||||
|   help = ( | ||||
|     'osu! api key. required if -input-file is not present. ' + | ||||
|     'can also be specified through the OSU_API_KEY ' + | ||||
|     'environment variable' | ||||
|   ) | ||||
| ) | ||||
|  | ||||
| parser.add_argument( | ||||
|   '-output-file', | ||||
|   default = 'test_suite.json', | ||||
|   help = 'dumps json to this file' | ||||
| ) | ||||
|  | ||||
| parser.add_argument( | ||||
|   '-input-file', | ||||
|   default = None, | ||||
|   help = ( | ||||
|     'loads test suite from this json file instead of ' | ||||
|     'fetching it from osu api. if set to "-", json will be ' | ||||
|     'read from standard input' | ||||
|   ) | ||||
| ) | ||||
|  | ||||
| args = parser.parse_args() | ||||
|  | ||||
| if args.key == None and 'OSU_API_KEY' in os.environ: | ||||
|   args.key = os.environ['OSU_API_KEY'] | ||||
|  | ||||
| # ------------------------------------------------------------------------- | ||||
|  | ||||
| osu_treset = time.time() + 60 | ||||
| osu_ncalls = 0 | ||||
|  | ||||
| def osu_get(conn, endpoint, paramsdict=None): | ||||
|   # GETs /api/endpoint?paramsdict&k=args.key from conn | ||||
|   # return json object, exits process on api errors | ||||
|   global osu_treset, osu_ncalls, args | ||||
|  | ||||
|   sys.stderr.write('%s %s\n' % (endpoint, str(paramsdict))) | ||||
|  | ||||
|   paramsdict['k'] = args.key | ||||
|   path = '/api/%s?%s' % (endpoint, urllib.urlencode(paramsdict)) | ||||
|  | ||||
|   while True: | ||||
|     while True: | ||||
|       if time.time() >= osu_treset: | ||||
|         osu_ncalls = 0 | ||||
|         osu_treset = time.time() + 60 | ||||
|         sys.stderr.write('\napi ready\n') | ||||
|  | ||||
|       if osu_ncalls < 60: | ||||
|         break | ||||
|       else: | ||||
|         sys.stderr.write('waiting for api cooldown...\r') | ||||
|         time.sleep(1) | ||||
|  | ||||
|  | ||||
|     try: | ||||
|       conn.request('GET', path) | ||||
|       osu_ncalls += 1 | ||||
|       r = conn.getresponse() | ||||
|  | ||||
|       raw = '' | ||||
|  | ||||
|       while True: | ||||
|         try: | ||||
|           raw += r.read() | ||||
|           break | ||||
|         except httplib.IncompleteRead as e: | ||||
|           raw += e.partial | ||||
|  | ||||
|       j = json.loads(raw) | ||||
|  | ||||
|       if 'error' in j: | ||||
|         sys.stderr.write('%s\n' % j['error']) | ||||
|         sys.exit(1) | ||||
|  | ||||
|       return j | ||||
|  | ||||
|     except (httplib.HTTPException, ValueError) as e: | ||||
|       sys.stderr.write('%s\n' % (traceback.format_exc())) | ||||
|  | ||||
|       try: | ||||
|         # prevents exceptions on next request if the | ||||
|         # response wasn't previously read due to errors | ||||
|         conn.getresponse().read() | ||||
|  | ||||
|       except httplib.HTTPException: | ||||
|         pass | ||||
|  | ||||
|       time.sleep(5) | ||||
|  | ||||
|  | ||||
| def gen_modstr(bitmask): | ||||
|   # generates c++ code for a mod combination's bitmask | ||||
|   mods = [] | ||||
|  | ||||
|   allmods = { | ||||
|     (1<< 0, 'nf'), (1<< 1, 'ez'), (1<< 2, 'td'), (1<< 3, 'hd'), | ||||
|     (1<< 4, 'hr'), (1<< 6, 'dt'), (1<< 8, 'ht'), | ||||
|     (1<< 9, 'nc'), (1<<10, 'fl'), (1<<12, 'so') | ||||
|   } | ||||
|  | ||||
|   for bit, string in allmods: | ||||
|     if bitmask & bit != 0: | ||||
|       mods.append(string) | ||||
|  | ||||
|   if len(mods) == 0: | ||||
|     return 'nomod' | ||||
|  | ||||
|   return ' | '.join(mods) | ||||
|  | ||||
| # ------------------------------------------------------------------------- | ||||
|  | ||||
| if args.key == None: | ||||
|   sys.stderr.write( | ||||
|     'please set OSU_API_KEY or pass it as a parameter\n' | ||||
|   ) | ||||
|   sys.exit(1) | ||||
|  | ||||
|  | ||||
| scores = [] | ||||
|  | ||||
| top_players = [ | ||||
|   [ 124493, 4787150, 2558286, 1777162, 2831793, 50265 ], | ||||
|   [ 3174184, 8276884, 5991961, 2774767 ] | ||||
| ] | ||||
|  | ||||
| if args.input_file == None: | ||||
|   # fetch a fresh test suite from osu api | ||||
|   osu = httplib.HTTPSConnection('osu.ppy.sh') | ||||
|  | ||||
|   for m in [0, 1]: | ||||
|     for u in top_players[m]: | ||||
|       params = { 'u': u, 'limit': 100, 'type': 'id', 'm': m } | ||||
|       batch = osu_get(osu, 'get_user_best', params) | ||||
|       for s in batch: | ||||
|         s['mode'] = m | ||||
|       scores += batch | ||||
|  | ||||
|   # temporarily removed, not all std scores are recalc'd | ||||
|   #params = { 'm': 0, 'since': '2015-11-26' } | ||||
|   #maps = osu_get(osu, 'get_beatmaps', params) | ||||
|  | ||||
|   # no taiko converts here because as explained below, tiny float | ||||
|   # errors can lead to completely broken conversions | ||||
|   for mode in [1]: | ||||
|     params = { 'm': mode, 'since': '2015-11-26' } | ||||
|     maps = osu_get(osu, 'get_beatmaps', params) | ||||
|  | ||||
|     for m in maps: | ||||
|       params = { 'b': m['beatmap_id'], 'm': mode } | ||||
|       map_scores = osu_get(osu, 'get_scores', params) | ||||
|  | ||||
|       if len(map_scores) == 0: | ||||
|         sys.stderr.write('W: map has no scores???\n') | ||||
|         continue | ||||
|  | ||||
|       # note: api also returns qualified and loved, so ignore | ||||
|       # maps that don't have pp in rankings | ||||
|       if not 'pp' in map_scores[0] or map_scores[0]['pp'] is None: | ||||
|         sys.stderr.write('W: ignoring loved/qualified map\n') | ||||
|         continue | ||||
|  | ||||
|       for s in map_scores: | ||||
|         s['beatmap_id'] = m['beatmap_id'] | ||||
|         s['mode'] = mode | ||||
|  | ||||
|       scores += map_scores | ||||
|  | ||||
|  | ||||
|   with open(args.output_file, 'w+') as f: | ||||
|     f.write(json.dumps(scores)) | ||||
|  | ||||
| else: | ||||
|   # load existing test suite from json file | ||||
|   with open(args.input_file, 'r') as f: | ||||
|     scores = json.loads(f.read()) | ||||
|   # sort by mode by map | ||||
|   scores.sort(key=lambda x: int(x['beatmap_id'])<<32|x['mode'], | ||||
|     reverse=True) | ||||
|  | ||||
|  | ||||
| print('/* this code was automatically generated by gentest.py */') | ||||
| print('') | ||||
|  | ||||
| # make code a little nicer by shortening mods | ||||
| allmods = { | ||||
|   'nf', 'ez', 'td', 'hd', 'hr', 'dt', 'ht', 'nc', 'fl', 'so', 'nomod' | ||||
| } | ||||
|  | ||||
| for mod in allmods: | ||||
|   print('#define %s MODS_%s' % (mod, mod.upper())) | ||||
|  | ||||
| print(''' | ||||
| typedef struct { | ||||
|   int mode; | ||||
|   int id; | ||||
|   int max_combo; | ||||
|   int n300, n100, n50, nmiss; | ||||
|   int mods; | ||||
|   double pp; | ||||
| } score_t; | ||||
|  | ||||
| score_t suite[] = {''') | ||||
|  | ||||
| seen_hashes = [] | ||||
|  | ||||
| for s in scores: | ||||
|   # due to tiny floating point errors, maps can even double | ||||
|   # in combo and not even lazer gets this right, taiko converts are hell | ||||
|   # so I'm just gonna exclude them | ||||
|   if s['mode'] == 1: | ||||
|     is_convert = False | ||||
|     with open('test_suite/'+s['beatmap_id']+'.osu') as f: | ||||
|       for line in f: | ||||
|         split = line.split(':') | ||||
|         if len(split) >= 2 and split[0] == 'Mode' and int(split[1]) == 0: | ||||
|           is_convert = True | ||||
|           break | ||||
|  | ||||
|     if is_convert: | ||||
|         continue | ||||
|  | ||||
|     # some taiko maps ignore combo scaling for no apparent reason | ||||
|     # so i will only include full combos for now | ||||
|     if int(s['countmiss']) != 0: | ||||
|         continue | ||||
|  | ||||
|   if s['pp'] is None: | ||||
|     continue | ||||
|  | ||||
|   # why is every value returned by osu api a string? | ||||
|   line = ( | ||||
|     '  { %d, %s, %s, %s, %s, %s, %s, %s, %s },' % | ||||
|     ( | ||||
|       s['mode'], s['beatmap_id'], s['maxcombo'], s['count300'], | ||||
|       s['count100'], s['count50'], s['countmiss'], | ||||
|       gen_modstr(int(s['enabled_mods'])), s['pp'] | ||||
|     ) | ||||
|   ) | ||||
|  | ||||
|   # don't include identical scores by different people | ||||
|   s = hashlib.sha1(line).digest() | ||||
|   if s in seen_hashes: | ||||
|     continue | ||||
|  | ||||
|   print(line) | ||||
|   seen_hashes.append(s) | ||||
|  | ||||
| print('};\n') | ||||
|  | ||||
| for mod in allmods: | ||||
|   print('#undef %s' % (mod)) | ||||
|  | ||||
							
								
								
									
										11
									
								
								test/pack_suite
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test/pack_suite
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir="$(dirname "$0")" | ||||
| wdir="$(realpath "$dir")" | ||||
|  | ||||
| olddir="$(pwd)" | ||||
| cd "$wdir" || exit $? | ||||
| tar -zcvf test_suite_$(date +%F).tar.gz test_suite/*.osu | ||||
| res=$? | ||||
| cd "$olddir" | ||||
| exit $res | ||||
							
								
								
									
										1
									
								
								test/suite_url
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/suite_url
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| https://github.com/Francesco149/oppai-ng/releases/download/2.3.2/test_suite_2019-02-19.tar.gz | ||||
							
								
								
									
										119
									
								
								test/test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								test/test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "../oppai.c" | ||||
| #include "test_suite.c" /* defines suite */ | ||||
|  | ||||
| #define ERROR_MARGIN 0.02f /* pp can be off by +- 2% */ | ||||
|  | ||||
| /* | ||||
|  * margin is actually | ||||
|  * - 3x for < 100pp | ||||
|  * - 2x for 100-200pp | ||||
|  * - 1.5x for 200-300pp | ||||
|  */ | ||||
|  | ||||
| void print_score(score_t* s) { | ||||
|   char mods_str_buf[20]; | ||||
|   char* mods_str = mods_str_buf; | ||||
|  | ||||
|   strcpy(mods_str, "nomod"); | ||||
|  | ||||
| #define m(mod) \ | ||||
|   if (s->mods & MODS_##mod) { \ | ||||
|     mods_str += sprintf(mods_str, #mod); \ | ||||
|   } \ | ||||
|  | ||||
|   m(HR) m(NC) m(HT) m(SO) m(NF) m(EZ) m(DT) m(FL) m(HD) | ||||
| #undef m | ||||
|  | ||||
|   printf("m=%d %u +%s %dx %dx300 %dx100 %dx50 %dxmiss %g pp\n", | ||||
|     s->mode, s->id, mods_str_buf, s->max_combo, s->n300, s->n100, | ||||
|     s->n50, s->nmiss, s->pp); | ||||
| } | ||||
|  | ||||
| int main() { | ||||
|   char fname_buf[4096]; | ||||
|   char* fname = fname_buf; | ||||
|   int i, n = (int)(sizeof(suite) / sizeof(suite[0])); | ||||
|   float max_err[2] = { 0, 0 }; | ||||
|   int max_err_map[2] = { 0, 0 }; | ||||
|   float avg_err[2] = { 0, 0 }; | ||||
|   int count[2] = { 0, 0 }; | ||||
|   float error = 0; | ||||
|   float error_percent = 0; | ||||
|   ezpp_t ez = ezpp_new(); | ||||
|   int err; | ||||
|   int last_id = 0; | ||||
|  | ||||
|   fname += sprintf(fname, "test_suite/"); | ||||
|  | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     score_t* s = &suite[i]; | ||||
|     float margin; | ||||
|     float pptotal; | ||||
|  | ||||
|     print_score(s); | ||||
|     if (s->id != last_id) { | ||||
|       sprintf(fname, "%u.osu", s->id); | ||||
|       last_id = s->id; | ||||
|       /* force reparse and don't reuse prev map ar/cs/od/hp */ | ||||
|       ezpp_set_base_cs(ez, -1); | ||||
|       ezpp_set_base_ar(ez, -1); | ||||
|       ezpp_set_base_od(ez, -1); | ||||
|       ezpp_set_base_hp(ez, -1); | ||||
|     } | ||||
|     ezpp_set_mods(ez, s->mods); | ||||
|     ezpp_set_accuracy(ez, s->n100, s->n50); | ||||
|     ezpp_set_nmiss(ez, s->nmiss); | ||||
|     ezpp_set_combo(ez, s->max_combo); | ||||
|     ezpp_set_mode_override(ez, s->mode); | ||||
|     err = ezpp(ez, fname_buf); | ||||
|     if (err < 0) { | ||||
|       printf("%s\n", errstr(err)); | ||||
|       exit(1); | ||||
|     } | ||||
|     pptotal = ezpp_pp(ez); | ||||
|     ++count[s->mode]; | ||||
|  | ||||
|     margin = (float)s->pp * ERROR_MARGIN; | ||||
|     if (s->pp < 100) { | ||||
|       margin *= 3; | ||||
|     } else if (s->pp < 200) { | ||||
|       margin *= 2; | ||||
|     } else if (s->pp < 300) { | ||||
|       margin *= 1.5f; | ||||
|     } | ||||
|  | ||||
|     error = (float)fabs(pptotal - (float)s->pp); | ||||
|     error_percent = error / (float)s->pp; | ||||
|     avg_err[s->mode] += error_percent; | ||||
|     if (error_percent > max_err[s->mode]) { | ||||
|       max_err[s->mode] = error_percent; | ||||
|       max_err_map[s->mode] = s->id; | ||||
|     } | ||||
|  | ||||
|     if (error >= margin) { | ||||
|       printf("failed test: got %g pp, expected %g\n", pptotal, s->pp); | ||||
|       exit(1); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   for (i = 0; i < 2; ++i) { | ||||
|     switch (i) { | ||||
|       case MODE_STD: puts("osu"); break; | ||||
|       case MODE_TAIKO: puts("taiko"); break; | ||||
|     } | ||||
|     avg_err[i] /= count[i]; | ||||
|     printf("%d scores\n", count[i]); | ||||
|     printf("avg err %f\n", avg_err[i]); | ||||
|     printf("max err %f on %d\n", max_err[i], max_err_map[i]); | ||||
|   } | ||||
|  | ||||
|   ezpp_free(ez); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										14745
									
								
								test/test_suite.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14745
									
								
								test/test_suite.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								valgrind
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								valgrind
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| valgrind --leak-check=full --track-origins=yes --show-leak-kinds=all "$@" | ||||
							
								
								
									
										15
									
								
								vcvarsall17.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vcvarsall17.ps1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # https://stackoverflow.com/questions/2124753/how-can-i-use-powershell-with-the-visual-studio-command-prompt | ||||
|  | ||||
| param ( | ||||
|   [string]$arch = "amd64" | ||||
| ) | ||||
|  | ||||
| Push-Location "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\Tools" | ||||
| cmd /c "VsDevCmd.bat -arch=$arch&set" | | ||||
| ForEach-Object { | ||||
|   if ($_ -match "=") { | ||||
|     $v = $_.split("="); set-item -force -path "ENV:\$($v[0])"  -value "$($v[1])" | ||||
|   } | ||||
| } | ||||
| Pop-Location | ||||
| Write-Host "`nVisual Studio 2017 Command Prompt variables set." -ForegroundColor Yellow | ||||
		Reference in New Issue
	
	Block a user