Skip to content

Commit

Permalink
feat: add automatic buffer size threshold detection
Browse files Browse the repository at this point in the history
Because buffer size depends so much on gamma to get correct results, 
it is now using automatic threshold detection.

Image is now processed to 8 bit which should speed up tesseract(3 times less bits
to dig through).

`sharp` module is now wrapped inside `ImageContainer` class, which acts as facede.

Fragments fail one by one, instead of all at once. This gives user more feedback what
went wrong.
  • Loading branch information
marcincichocki authored Apr 15, 2021
1 parent 4f7832d commit 4912ce9
Show file tree
Hide file tree
Showing 23 changed files with 972 additions and 680 deletions.
Binary file added src/bp-registry/2560x1440/g050.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/bp-registry/2560x1440/g150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions src/bp-registry/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,38 @@
"1C", "1C", "E9", "1C", "7A", "E9", "1C"
],
"bufferSize": 8
},
{
"fileName": "g050.png",
"daemons": [
["BD", "BD"],
["E9", "BD"],
["55", "1C", "E9"]
],
"grid": [
"55", "55", "1C", "E9", "BD",
"1C", "E9", "55", "55", "1C",
"E9", "E9", "BD", "1C", "1C",
"BD", "1C", "BD", "BD", "55",
"BD", "1C", "E9", "BD", "BD"
],
"bufferSize": 7
},
{
"fileName": "g150.png",
"daemons": [
["55", "55", "1C"],
["1C", "55", "E9"],
["E9", "1C", "1C", "1C"]
],
"grid": [
"55", "E9", "55", "1C", "1C",
"BD", "1C", "1C", "55", "55",
"1C", "55", "E9", "1C", "1C",
"BD", "55", "1C", "55", "1C",
"BD", "1C", "1C", "1C", "55"
],
"bufferSize": 7
}
],
"3840x2160": [
Expand Down
14 changes: 8 additions & 6 deletions src/common/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,38 @@
"LOADING_WORKERS_START": "Loading tesseract..",
"CHOOSE_MONITOR": "On which monitor Cyberpunk 2077 is running?",
"READY": "Listening for key bind..",
"OCR_DATA_INVALID": "OCR data is not valid. Skipping.",
"CAPTURE_SCREEN": "Capturing screen \"{0}\"..",
"OCR_START": "Starting OCR..",
"SOLVER_START": "Solving..",
"DEBUG": "Saving debug info..",
"SOLVER_DONE": "Success.",
"UNKNOWN_KEY_ERROR": "Unknown key: \"{0}\".",
"NEW_VERSION_AVAILABLE": "There is new version({0}) available. Download and exit?",
"UNSUPORTED_RESOLUTION_ERROR": "Unsuported resolution: \"{0}\".",
"UNSUPORTED_OS": "Only Windows is supported.",
"INVALID_LANG_ERROR": "Invalid language code. Expected one of {0} but got \"{1}\".",
"NO_SOLUTION": "Could not find any solution. Skipping."
"NO_SOLUTION": "Could not find any solution. Skipping.",
"GRID_INVALID": "Could not recognize grid fragment. Skipping.",
"DAEMONS_INVALID": "Could not recognize daemons fragment. Skipping.",
"BUFFER_SIZE_INVALID": "Could not recognize buffer size fragment. Skipping."
},
"pl": {
"CHECK_FOR_UPDATES": "Sprawdzam dostępność aktualizacji..",
"UP_TO_DATE": "Aktualna wersja programu.",
"LOADING_WORKERS_START": "Ładowanie tesseracta..",
"CHOOSE_MONITOR": "Na którym monitorze jest uruchomiony Cyberpunk 2077?",
"READY": "Czekam na skrót..",
"OCR_DATA_INVALID": "Dane z OCRa są niepoprawne. Pomijam.",
"CAPTURE_SCREEN": "Robię zrzut ekranu \"{0}\"..",
"OCR_START": "Rozpoczynam OCR..",
"SOLVER_START": "Rozwiązuję..",
"DEBUG": "Zapisuję dane debugowania..",
"SOLVER_DONE": "Sukces.",
"UNKNOWN_KEY_ERROR": "Nienzany klucz: \"{0}\".",
"NEW_VERSION_AVAILABLE": "Jest dostępna nowa wersja({0}). Pobrać i wyjść?",
"UNSUPORTED_RESOLUTION_ERROR": "Nieobsługiwana rozdzielczość: \"{0}\".",
"UNSUPORTED_OS": "Tylko system Windows jest obsługiwany.",
"INVALID_LANG_ERROR": "Niepoprawny kod jezyka. Oczekiwano jednego z listy {0} ale otrzymano \"{1}\".",
"NO_SOLUTION": "Nie znaleziono żadnego rozwiązania. Pomijam."
"NO_SOLUTION": "Nie znaleziono żadnego rozwiązania. Pomijam.",
"GRID_INVALID": "Nie udało się rozpoznać fragmentu \"grid\". Pomijam.",
"DAEMONS_INVALID": "Nie udało się rozpoznać fragmentu \"daemons\". Pomijam.",
"BUFFER_SIZE_INVALID": "Nie udało się rozpoznać fragmentu \"bufferSize\". Pomijam."
}
}
14 changes: 13 additions & 1 deletion src/common/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { chunk, memoize, unique, uniqueBy, uniqueWith } from './util';
import {
chunk,
getClosest,
memoize,
unique,
uniqueBy,
uniqueWith,
} from './util';

describe('utils', () => {
it('should create chunks', () => {
Expand Down Expand Up @@ -45,4 +52,9 @@ describe('utils', () => {
[2, 3],
]);
});

it('should find closest number', () => {
expect(getClosest(4, [1, 5])).toBe(5);
expect(getClosest(900, [720, 1080, 1440])).toBe(720);
});
});
8 changes: 8 additions & 0 deletions src/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,11 @@ export function chunk(str: string, size: number) {

return chunks;
}

export function getClosest(n: number, list: number[]) {
const distances = list.map((x) => Math.abs(n - x));
const min = Math.min(...distances);
const index = distances.indexOf(min);

return list[index];
}
70 changes: 3 additions & 67 deletions src/core/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { unique, uniqueBy } from '@/common';
import sharp from 'sharp';
import { uniqueBy } from '@/common';
import { BreachProtocolResult } from './game';
import { BreachProtocolFragmentResult } from './ocr/base';
import { Daemon, Sequence } from './sequence';

export const HEX_NUMBERS = ['E9', '1C', 'BD', '55', '7A', 'FF'] as const;
Expand Down Expand Up @@ -117,43 +117,12 @@ export class BreachProtocolValidationError extends Error {

constructor(
public message: string,
public readonly data: BreachProtocolRawData
public readonly result: BreachProtocolFragmentResult<any, any, any>
) {
super(message);
}
}

function validateSymbols(symbols: string[]) {
if (!symbols.length) {
// [].every(() => {}) returns true
return false;
}

return symbols
.filter(unique)
.every((s) => HEX_NUMBERS.includes(s as HexNumber));
}

function validateBufferSize(n: number) {
return Number.isInteger(n) && n >= BUFFER_SIZE_MIN && n <= BUFFER_SIZE_MAX;
}

function isSquare(n: number) {
return n > 0 && Math.sqrt(n) % 1 === 0;
}

export function isRawDataValid({
grid,
daemons,
bufferSize,
}: BreachProtocolRawData) {
const isGridValid = validateSymbols(grid) && isSquare(grid.length);
const areDaemonsValid = validateSymbols(daemons.flat());
const isBufferValid = validateBufferSize(bufferSize);

return isGridValid && areDaemonsValid && isBufferValid;
}

export interface BreachProtocolExitStrategy {
willExit: boolean;
shouldForceClose: boolean;
Expand All @@ -178,36 +147,3 @@ export function resolveExitStrategy(
shouldForceClose,
};
}

export const BREACH_PROTOCOL_ASPECT_RATIO = 16 / 9;

/** Return aspect ratio for given resolution and handle edge cases. */
export function getAspectRatio(x: number, y: number) {
// WXGA, very close to 16:9
// TODO: test if this resolution correctly ocr buffer size.
// https://en.wikipedia.org/wiki/Graphics_display_resolution#WXGA
if (y === 768 && (x === 1366 || x === 1360)) {
return BREACH_PROTOCOL_ASPECT_RATIO;
}

return x / y;
}

export function getCroppedBoundingBox(x: number, y: number): sharp.Region {
// Resolution with ratio less than one have horizontal black
// bars, and ratio greater than one have vertical.
// Resolutions with ratio equal to 1 are in 16:9 aspect ratio
// and do not require cropping.
const ratio = getAspectRatio(x, y) / BREACH_PROTOCOL_ASPECT_RATIO;
const width = ratio > 1 ? y * BREACH_PROTOCOL_ASPECT_RATIO : x;
const height = ratio < 1 ? x / BREACH_PROTOCOL_ASPECT_RATIO : y;
const left = (x - width) / 2;
const top = (y - height) / 2;

return {
width,
height,
left,
top,
};
}
53 changes: 0 additions & 53 deletions src/core/configs.json

This file was deleted.

Loading

0 comments on commit 4912ce9

Please sign in to comment.