Heck yeah back to double quotes

This commit is contained in:
Vince Au
2020-07-16 12:53:25 +10:00
parent b400561fb5
commit 5e42a1129d
27 changed files with 422 additions and 422 deletions

View File

@@ -1,7 +1,7 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
trailingComma: "all",
singleQuote: false,
printWidth: 120,
tabWidth: 2,
};

View File

@@ -1,10 +1,10 @@
/* eslint-disable no-param-reassign */
import _ from 'lodash';
import { openSlpFile, closeSlpFile, iterateEvents, getMetadata, SlpInputSource, SlpReadInput } from './utils/slpReader';
import _ from "lodash";
import { openSlpFile, closeSlpFile, iterateEvents, getMetadata, SlpInputSource, SlpReadInput } from "./utils/slpReader";
// Type imports
import { MetadataType, GameStartType, GameEndType } from './types';
import { SlpParser, SlpParserEvent } from './utils/slpParser';
import { MetadataType, GameStartType, GameEndType } from "./types";
import { SlpParser, SlpParserEvent } from "./utils/slpParser";
import {
StockComputer,
ComboComputer,
@@ -18,7 +18,7 @@ import {
getSinglesPlayerPermutationsFromSettings,
generateOverallStats,
StatOptions,
} from './stats';
} from "./stats";
/**
* Slippi Game class that wraps a file
@@ -48,7 +48,7 @@ export class SlippiGame {
buffer: input,
};
} else {
throw new Error('Cannot create SlippiGame with input of that type');
throw new Error("Cannot create SlippiGame with input of that type");
}
// Set up stats calculation

View File

@@ -1,4 +1,4 @@
import { decode, encode } from '@shelacek/ubjson';
import { decode, encode } from "@shelacek/ubjson";
export enum CommunicationType {
HANDSHAKE = 1,

View File

@@ -1,20 +1,20 @@
import net from 'net';
import { EventEmitter } from 'events';
import net from "net";
import { EventEmitter } from "events";
import inject from 'reconnect-core';
import inject from "reconnect-core";
import { ConsoleCommunication, CommunicationType, CommunicationMessage } from './communication';
import { ConsoleCommunication, CommunicationType, CommunicationMessage } from "./communication";
export const NETWORK_MESSAGE = 'HELO\0';
export const NETWORK_MESSAGE = "HELO\0";
const DEFAULT_CONNECTION_TIMEOUT_MS = 20000;
export enum ConnectionEvent {
HANDSHAKE = 'handshake',
STATUS_CHANGE = 'statusChange',
DATA = 'data',
INFO = 'loginfo',
WARN = 'logwarn',
HANDSHAKE = "handshake",
STATUS_CHANGE = "statusChange",
DATA = "data",
INFO = "loginfo",
WARN = "logwarn",
}
export enum ConnectionStatus {
@@ -43,15 +43,15 @@ export interface ConnectionSettings {
}
enum CommunicationState {
INITIAL = 'initial',
LEGACY = 'legacy',
NORMAL = 'normal',
INITIAL = "initial",
LEGACY = "legacy",
NORMAL = "normal",
}
const defaultConnectionDetails: ConnectionDetails = {
consoleNick: 'unknown',
consoleNick: "unknown",
gameDataCursor: Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 0]),
version: '',
version: "",
clientToken: 0,
};
@@ -87,7 +87,7 @@ export class ConsoleConnection extends EventEmitter {
public constructor() {
super();
this.ipAddress = '0.0.0.0';
this.ipAddress = "0.0.0.0";
this.port = Ports.DEFAULT;
this.clientsByPort = [];
this.connectionsByPort = [];
@@ -160,19 +160,19 @@ export class ConsoleConnection extends EventEmitter {
{
initialDelay: 2000,
maxDelay: 10000,
strategy: 'fibonacci',
strategy: "fibonacci",
failAfter: Infinity,
},
(client) => {
this.clientsByPort[port] = client;
let commState: CommunicationState = CommunicationState.INITIAL;
client.on('data', (data) => {
client.on("data", (data) => {
if (commState === CommunicationState.INITIAL) {
commState = this._getInitialCommState(data);
console.log(`Connected to ${this.ipAddress}:${this.port} with type: ${commState}`);
this._setStatus(ConnectionStatus.CONNECTED);
console.log(data.toString('hex'));
console.log(data.toString("hex"));
}
if (commState === CommunicationState.LEGACY) {
@@ -185,7 +185,7 @@ export class ConsoleConnection extends EventEmitter {
try {
consoleComms.receive(data);
} catch (err) {
console.warn('Failed to process new data from server...', {
console.warn("Failed to process new data from server...", {
error: err,
prevDataBuf: consoleComms.getReceiveBuffer(),
rcvData: data,
@@ -206,19 +206,19 @@ export class ConsoleConnection extends EventEmitter {
}
});
client.on('timeout', () => {
client.on("timeout", () => {
// const previouslyConnected = this.connectionStatus === ConnectionStatus.CONNECTED;
console.warn(`Attempted connection to ${this.ipAddress}:${this.port} timed out after ${timeout}ms`);
client.destroy();
});
client.on('end', () => {
console.log('disconnect');
client.on("end", () => {
console.log("disconnect");
client.destroy();
});
client.on('close', () => {
console.log('connection was closed');
client.on("close", () => {
console.log("connection was closed");
});
const handshakeMsgOut = consoleComms.genHandshakeOut(
@@ -235,10 +235,10 @@ export class ConsoleConnection extends EventEmitter {
this._setStatus(ConnectionStatus.CONNECTING);
};
connection.on('connect', setConnectingStatus);
connection.on('reconnect', setConnectingStatus);
connection.on("connect", setConnectingStatus);
connection.on("reconnect", setConnectingStatus);
connection.on('disconnect', () => {
connection.on("disconnect", () => {
// If one of the connections was successful, we no longer need to try connecting this one
this.connectionsByPort.forEach((iConn, iPort) => {
if (iPort === port || !iConn.connected) {
@@ -255,12 +255,12 @@ export class ConsoleConnection extends EventEmitter {
// TODO: Connecting... forever
});
connection.on('error', (error) => {
connection.on("error", (error) => {
console.error(`Connection on port ${port} encountered an error.`, error);
});
this.connectionsByPort[port] = connection;
console.log('Starting connection');
console.log("Starting connection");
connection.connect(port);
}
@@ -268,7 +268,7 @@ export class ConsoleConnection extends EventEmitter {
* Terminate the current connection.
*/
public disconnect(): void {
console.log('Disconnect request');
console.log("Disconnect request");
this.connectionsByPort.forEach((connection) => {
// Prevent reconnections and disconnect
@@ -312,19 +312,19 @@ export class ConsoleConnection extends EventEmitter {
const cmp = Buffer.compare(this.connDetails.gameDataCursor, readPos);
if (!message.payload.forcePos && cmp !== 0) {
console.warn(
'Position of received data is not what was expected. Expected, Received:',
"Position of received data is not what was expected. Expected, Received:",
this.connDetails.gameDataCursor,
readPos,
);
// The readPos is not the one we are waiting on, throw error
throw new Error('Position of received data is incorrect.');
throw new Error("Position of received data is incorrect.");
}
if (message.payload.forcePos) {
console.warn(
'Overflow occured in Nintendont, data has likely been skipped and replay corrupted. ' +
'Expected, Received:',
"Overflow occured in Nintendont, data has likely been skipped and replay corrupted. " +
"Expected, Received:",
this.connDetails.gameDataCursor,
readPos,
);

View File

@@ -1 +1 @@
export * from './connection';
export * from "./connection";

View File

@@ -1,21 +1,21 @@
import { SlippiGame } from './SlippiGame';
import { SlippiGame } from "./SlippiGame";
// Export melee util types
export * from './melee';
export * from "./melee";
// Export types
export * from './types';
export * from './stats';
export * from "./types";
export * from "./stats";
// Utils
export * from './utils/slpFile';
export * from './utils/slpStream';
export * from './utils/slpParser';
export * from "./utils/slpFile";
export * from "./utils/slpStream";
export * from "./utils/slpParser";
// Console networking
export * from './console';
export * from "./console";
// Support both named and default exports
export * from './SlippiGame';
export * from "./SlippiGame";
export default SlippiGame;

View File

@@ -6,12 +6,12 @@ export function getDeathDirection(actionStateId: number) {
switch (actionStateId) {
case 0:
return 'down';
return "down";
case 1:
return 'left';
return "left";
case 2:
return 'right';
return "right";
default:
return 'up';
return "up";
}
}

View File

@@ -10,159 +10,159 @@ export interface CharacterInfo {
const externalCharacters: CharacterInfo[] = [
{
id: 0,
name: 'Captain Falcon',
shortName: 'Falcon',
colors: ['Default', 'Black', 'Red', 'White', 'Green', 'Blue'],
name: "Captain Falcon",
shortName: "Falcon",
colors: ["Default", "Black", "Red", "White", "Green", "Blue"],
},
{
id: 1,
name: 'Donkey Kong',
shortName: 'DK',
colors: ['Default', 'Black', 'Red', 'Blue', 'Green'],
name: "Donkey Kong",
shortName: "DK",
colors: ["Default", "Black", "Red", "Blue", "Green"],
},
{
id: 2,
name: 'Fox',
shortName: 'Fox',
colors: ['Default', 'Red', 'Blue', 'Green'],
name: "Fox",
shortName: "Fox",
colors: ["Default", "Red", "Blue", "Green"],
},
{
id: 3,
name: 'Mr. Game & Watch',
shortName: 'G&W',
colors: ['Default', 'Red', 'Blue', 'Green'],
name: "Mr. Game & Watch",
shortName: "G&W",
colors: ["Default", "Red", "Blue", "Green"],
},
{
id: 4,
name: 'Kirby',
shortName: 'Kirby',
colors: ['Default', 'Yellow', 'Blue', 'Red', 'Green', 'White'],
name: "Kirby",
shortName: "Kirby",
colors: ["Default", "Yellow", "Blue", "Red", "Green", "White"],
},
{
id: 5,
name: 'Bowser',
shortName: 'Bowser',
colors: ['Default', 'Red', 'Blue', 'Black'],
name: "Bowser",
shortName: "Bowser",
colors: ["Default", "Red", "Blue", "Black"],
},
{
id: 6,
name: 'Link',
shortName: 'Link',
colors: ['Default', 'Red', 'Blue', 'Black', 'White'],
name: "Link",
shortName: "Link",
colors: ["Default", "Red", "Blue", "Black", "White"],
},
{
id: 7,
name: 'Luigi',
shortName: 'Luigi',
colors: ['Default', 'White', 'Blue', 'Red'],
name: "Luigi",
shortName: "Luigi",
colors: ["Default", "White", "Blue", "Red"],
},
{
id: 8,
name: 'Mario',
shortName: 'Mario',
colors: ['Default', 'Yellow', 'Black', 'Blue', 'Green'],
name: "Mario",
shortName: "Mario",
colors: ["Default", "Yellow", "Black", "Blue", "Green"],
},
{
id: 9,
name: 'Marth',
shortName: 'Marth',
colors: ['Default', 'Red', 'Green', 'Black', 'White'],
name: "Marth",
shortName: "Marth",
colors: ["Default", "Red", "Green", "Black", "White"],
},
{
id: 10,
name: 'Mewtwo',
shortName: 'Mewtwo',
colors: ['Default', 'Red', 'Blue', 'Green'],
name: "Mewtwo",
shortName: "Mewtwo",
colors: ["Default", "Red", "Blue", "Green"],
},
{
id: 11,
name: 'Ness',
shortName: 'Ness',
colors: ['Default', 'Yellow', 'Blue', 'Green'],
name: "Ness",
shortName: "Ness",
colors: ["Default", "Yellow", "Blue", "Green"],
},
{
id: 12,
name: 'Peach',
shortName: 'Peach',
colors: ['Default', 'Daisy', 'White', 'Blue', 'Green'],
name: "Peach",
shortName: "Peach",
colors: ["Default", "Daisy", "White", "Blue", "Green"],
},
{
id: 13,
name: 'Pikachu',
shortName: 'Pikachu',
colors: ['Default', 'Red', 'Party Hat', 'Cowboy Hat'],
name: "Pikachu",
shortName: "Pikachu",
colors: ["Default", "Red", "Party Hat", "Cowboy Hat"],
},
{
id: 14,
name: 'Ice Climbers',
shortName: 'ICs',
colors: ['Default', 'Green', 'Orange', 'Red'],
name: "Ice Climbers",
shortName: "ICs",
colors: ["Default", "Green", "Orange", "Red"],
},
{
id: 15,
name: 'Jigglypuff',
shortName: 'Puff',
colors: ['Default', 'Red', 'Blue', 'Headband', 'Crown'],
name: "Jigglypuff",
shortName: "Puff",
colors: ["Default", "Red", "Blue", "Headband", "Crown"],
},
{
id: 16,
name: 'Samus',
shortName: 'Samus',
colors: ['Default', 'Pink', 'Black', 'Green', 'Purple'],
name: "Samus",
shortName: "Samus",
colors: ["Default", "Pink", "Black", "Green", "Purple"],
},
{
id: 17,
name: 'Yoshi',
shortName: 'Yoshi',
colors: ['Default', 'Red', 'Blue', 'Yellow', 'Pink', 'Cyan'],
name: "Yoshi",
shortName: "Yoshi",
colors: ["Default", "Red", "Blue", "Yellow", "Pink", "Cyan"],
},
{
id: 18,
name: 'Zelda',
shortName: 'Zelda',
colors: ['Default', 'Red', 'Blue', 'Green', 'White'],
name: "Zelda",
shortName: "Zelda",
colors: ["Default", "Red", "Blue", "Green", "White"],
},
{
id: 19,
name: 'Sheik',
shortName: 'Sheik',
colors: ['Default', 'Red', 'Blue', 'Green', 'White'],
name: "Sheik",
shortName: "Sheik",
colors: ["Default", "Red", "Blue", "Green", "White"],
},
{
id: 20,
name: 'Falco',
shortName: 'Falco',
colors: ['Default', 'Red', 'Blue', 'Green'],
name: "Falco",
shortName: "Falco",
colors: ["Default", "Red", "Blue", "Green"],
},
{
id: 21,
name: 'Young Link',
shortName: 'YLink',
colors: ['Default', 'Red', 'Blue', 'White', 'Black'],
name: "Young Link",
shortName: "YLink",
colors: ["Default", "Red", "Blue", "White", "Black"],
},
{
id: 22,
name: 'Dr. Mario',
shortName: 'Doc',
colors: ['Default', 'Red', 'Blue', 'Green', 'Black'],
name: "Dr. Mario",
shortName: "Doc",
colors: ["Default", "Red", "Blue", "Green", "Black"],
},
{
id: 23,
name: 'Roy',
shortName: 'Roy',
colors: ['Default', 'Red', 'Blue', 'Green', 'Yellow'],
name: "Roy",
shortName: "Roy",
colors: ["Default", "Red", "Blue", "Green", "Yellow"],
},
{
id: 24,
name: 'Pichu',
shortName: 'Pichu',
colors: ['Default', 'Red', 'Blue', 'Green'],
name: "Pichu",
shortName: "Pichu",
colors: ["Default", "Red", "Blue", "Green"],
},
{
id: 25,
name: 'Ganondorf',
shortName: 'Ganon',
colors: ['Default', 'Red', 'Blue', 'Green', 'Purple'],
name: "Ganondorf",
shortName: "Ganon",
colors: ["Default", "Red", "Blue", "Green", "Purple"],
},
];

View File

@@ -1,6 +1,6 @@
import * as animations from './animations';
import * as characters from './characters';
import * as moves from './moves';
import * as stages from './stages';
import * as animations from "./animations";
import * as characters from "./characters";
import * as moves from "./moves";
import * as stages from "./stages";
export { animations, characters, moves, stages };

View File

@@ -6,161 +6,161 @@ export interface Move {
export const UnknownMove: Move = {
id: -1,
name: 'Unknown Move',
shortName: 'unknown',
name: "Unknown Move",
shortName: "unknown",
};
const moves: { [id: number]: Move } = {
1: {
// This includes all thrown items, zair, luigi's taunt, samus bombs, etc
id: 1,
name: 'Miscellaneous',
shortName: 'misc',
name: "Miscellaneous",
shortName: "misc",
},
2: {
id: 2,
name: 'Jab',
shortName: 'jab',
name: "Jab",
shortName: "jab",
},
3: {
id: 3,
name: 'Jab',
shortName: 'jab',
name: "Jab",
shortName: "jab",
},
4: {
id: 4,
name: 'Jab',
shortName: 'jab',
name: "Jab",
shortName: "jab",
},
5: {
id: 5,
name: 'Rapid Jabs',
shortName: 'rapid-jabs',
name: "Rapid Jabs",
shortName: "rapid-jabs",
},
6: {
id: 6,
name: 'Dash Attack',
shortName: 'dash',
name: "Dash Attack",
shortName: "dash",
},
7: {
id: 7,
name: 'Forward Tilt',
shortName: 'ftilt',
name: "Forward Tilt",
shortName: "ftilt",
},
8: {
id: 8,
name: 'Up Tilt',
shortName: 'utilt',
name: "Up Tilt",
shortName: "utilt",
},
9: {
id: 9,
name: 'Down Tilt',
shortName: 'dtilt',
name: "Down Tilt",
shortName: "dtilt",
},
10: {
id: 10,
name: 'Forward Smash',
shortName: 'fsmash',
name: "Forward Smash",
shortName: "fsmash",
},
11: {
id: 11,
name: 'Up Smash',
shortName: 'usmash',
name: "Up Smash",
shortName: "usmash",
},
12: {
id: 12,
name: 'Down Smash',
shortName: 'dsmash',
name: "Down Smash",
shortName: "dsmash",
},
13: {
id: 13,
name: 'Neutral Air',
shortName: 'nair',
name: "Neutral Air",
shortName: "nair",
},
14: {
id: 14,
name: 'Forward Air',
shortName: 'fair',
name: "Forward Air",
shortName: "fair",
},
15: {
id: 15,
name: 'Back Air',
shortName: 'bair',
name: "Back Air",
shortName: "bair",
},
16: {
id: 16,
name: 'Up Air',
shortName: 'uair',
name: "Up Air",
shortName: "uair",
},
17: {
id: 17,
name: 'Down Air',
shortName: 'dair',
name: "Down Air",
shortName: "dair",
},
18: {
id: 18,
name: 'Neutral B',
shortName: 'neutral-b',
name: "Neutral B",
shortName: "neutral-b",
},
19: {
id: 19,
name: 'Side B',
shortName: 'side-b',
name: "Side B",
shortName: "side-b",
},
20: {
id: 20,
name: 'Up B',
shortName: 'up-b',
name: "Up B",
shortName: "up-b",
},
21: {
id: 21,
name: 'Down B',
shortName: 'down-b',
name: "Down B",
shortName: "down-b",
},
50: {
id: 50,
name: 'Getup Attack',
shortName: 'getup',
name: "Getup Attack",
shortName: "getup",
},
51: {
id: 51,
name: 'Getup Attack (Slow)',
shortName: 'getup-slow',
name: "Getup Attack (Slow)",
shortName: "getup-slow",
},
52: {
id: 52,
name: 'Grab Pummel',
shortName: 'pummel',
name: "Grab Pummel",
shortName: "pummel",
},
53: {
id: 53,
name: 'Forward Throw',
shortName: 'fthrow',
name: "Forward Throw",
shortName: "fthrow",
},
54: {
id: 54,
name: 'Back Throw',
shortName: 'bthrow',
name: "Back Throw",
shortName: "bthrow",
},
55: {
id: 55,
name: 'Up Throw',
shortName: 'uthrow',
name: "Up Throw",
shortName: "uthrow",
},
56: {
id: 56,
name: 'Down Throw',
shortName: 'dthrow',
name: "Down Throw",
shortName: "dthrow",
},
61: {
id: 61,
name: 'Edge Attack (Slow)',
shortName: 'edge-slow',
name: "Edge Attack (Slow)",
shortName: "edge-slow",
},
62: {
id: 62,
name: 'Edge Attack',
shortName: 'edge',
name: "Edge Attack",
shortName: "edge",
},
};

View File

@@ -6,11 +6,11 @@ export interface Stage {
const stages: { [id: number]: Stage } = {
2: {
id: 2,
name: 'Fountain of Dreams',
name: "Fountain of Dreams",
},
3: {
id: 3,
name: 'Pokémon Stadium',
name: "Pokémon Stadium",
},
4: {
id: 4,
@@ -18,15 +18,15 @@ const stages: { [id: number]: Stage } = {
},
5: {
id: 5,
name: 'Kongo Jungle',
name: "Kongo Jungle",
},
6: {
id: 6,
name: 'Brinstar',
name: "Brinstar",
},
7: {
id: 7,
name: 'Corneria',
name: "Corneria",
},
8: {
id: 8,
@@ -34,31 +34,31 @@ const stages: { [id: number]: Stage } = {
},
9: {
id: 9,
name: 'Onett',
name: "Onett",
},
10: {
id: 10,
name: 'Mute City',
name: "Mute City",
},
11: {
id: 11,
name: 'Rainbow Cruise',
name: "Rainbow Cruise",
},
12: {
id: 12,
name: 'Jungle Japes',
name: "Jungle Japes",
},
13: {
id: 13,
name: 'Great Bay',
name: "Great Bay",
},
14: {
id: 14,
name: 'Hyrule Temple',
name: "Hyrule Temple",
},
15: {
id: 15,
name: 'Brinstar Depths',
name: "Brinstar Depths",
},
16: {
id: 16,
@@ -66,47 +66,47 @@ const stages: { [id: number]: Stage } = {
},
17: {
id: 17,
name: 'Green Greens',
name: "Green Greens",
},
18: {
id: 18,
name: 'Fourside',
name: "Fourside",
},
19: {
id: 19,
name: 'Mushroom Kingdom I',
name: "Mushroom Kingdom I",
},
20: {
id: 20,
name: 'Mushroom Kingdom II',
name: "Mushroom Kingdom II",
},
22: {
id: 22,
name: 'Venom',
name: "Venom",
},
23: {
id: 23,
name: 'Poké Floats',
name: "Poké Floats",
},
24: {
id: 24,
name: 'Big Blue',
name: "Big Blue",
},
25: {
id: 25,
name: 'Icicle Mountain',
name: "Icicle Mountain",
},
26: {
id: 26,
name: 'Icetop',
name: "Icetop",
},
27: {
id: 27,
name: 'Flat Zone',
name: "Flat Zone",
},
28: {
id: 28,
name: 'Dream Land N64',
name: "Dream Land N64",
},
29: {
id: 29,
@@ -114,15 +114,15 @@ const stages: { [id: number]: Stage } = {
},
30: {
id: 30,
name: 'Kongo Jungle N64',
name: "Kongo Jungle N64",
},
31: {
id: 31,
name: 'Battlefield',
name: "Battlefield",
},
32: {
id: 32,
name: 'Final Destination',
name: "Final Destination",
},
};

View File

@@ -1,7 +1,7 @@
// @flow
import _ from 'lodash';
import { State, PlayerIndexedType, FrameEntryType, ActionCountsType } from './common';
import { StatComputer } from './stats';
import _ from "lodash";
import { State, PlayerIndexedType, FrameEntryType, ActionCountsType } from "./common";
import { StatComputer } from "./stats";
// Frame pattern that indicates a dash dance turn was executed
const dashDanceAnimations = [State.DASH, State.TURN, State.DASH];
@@ -114,19 +114,19 @@ function handleActionCompute(state: PlayerActionState, indices: PlayerIndexedTyp
// Increment counts based on conditions
const didDashDance = _.isEqual(last3Frames, dashDanceAnimations);
incrementCount('dashDanceCount', didDashDance);
incrementCount("dashDanceCount", didDashDance);
const didRoll = didStartRoll(currentAnimation, prevAnimation);
incrementCount('rollCount', didRoll);
incrementCount("rollCount", didRoll);
const didSpotDodge = didStartSpotDodge(currentAnimation, prevAnimation);
incrementCount('spotDodgeCount', didSpotDodge);
incrementCount("spotDodgeCount", didSpotDodge);
const didAirDodge = didStartAirDodge(currentAnimation, prevAnimation);
incrementCount('airDodgeCount', didAirDodge);
incrementCount("airDodgeCount", didAirDodge);
const didGrabLedge = didStartLedgegrab(currentAnimation, prevAnimation);
incrementCount('ledgegrabCount', didGrabLedge);
incrementCount("ledgegrabCount", didGrabLedge);
// Handles wavedash detection (and waveland)
handleActionWavedash(state.playerCounts, state.animations);

View File

@@ -1,8 +1,8 @@
import _ from 'lodash';
import { PostFrameUpdateType } from '../types';
import { FrameEntryType, FramesType, MoveLandedType, ComboType, PlayerIndexedType } from './common';
import { isDamaged, isGrabbed, calcDamageTaken, isTeching, didLoseStock, Timers, isDown, isDead } from './common';
import { StatComputer } from './stats';
import _ from "lodash";
import { PostFrameUpdateType } from "../types";
import { FrameEntryType, FramesType, MoveLandedType, ComboType, PlayerIndexedType } from "./common";
import { isDamaged, isGrabbed, calcDamageTaken, isTeching, didLoseStock, Timers, isDown, isDead } from "./common";
import { StatComputer } from "./stats";
interface ComboState {
combo: ComboType | null;
@@ -51,11 +51,11 @@ function handleComboCompute(
const playerFrame: PostFrameUpdateType = frame.players[indices.playerIndex].post;
// FIXME: use type PostFrameUpdateType instead of any
// This is because the default value {} should not be casted as a type of PostFrameUpdateType
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.playerIndex, 'post'], {});
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.playerIndex, "post"], {});
const opponentFrame: PostFrameUpdateType = frame.players[indices.opponentIndex].post;
// FIXME: use type PostFrameUpdateType instead of any
// This is because the default value {} should not be casted as a type of PostFrameUpdateType
const prevOpponentFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.opponentIndex, 'post'], {});
const prevOpponentFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.opponentIndex, "post"], {});
const opntIsDamaged = isDamaged(opponentFrame.actionStateId);
const opntIsGrabbed = isGrabbed(opponentFrame.actionStateId);

View File

@@ -1,5 +1,5 @@
import _ from 'lodash';
import { PostFrameUpdateType, GameStartType, PreFrameUpdateType, ItemUpdateType } from '../types';
import _ from "lodash";
import { PostFrameUpdateType, GameStartType, PreFrameUpdateType, ItemUpdateType } from "../types";
export interface FrameEntryType {
frame: number;
@@ -214,8 +214,8 @@ export function isDead(state: number): boolean {
}
export function calcDamageTaken(frame: PostFrameUpdateType, prevFrame: PostFrameUpdateType): number {
const percent = _.get(frame, 'percent', 0);
const prevPercent = _.get(prevFrame, 'percent', 0);
const percent = _.get(frame, "percent", 0);
const prevPercent = _.get(prevFrame, "percent", 0);
return percent - prevPercent;
}

View File

@@ -1,8 +1,8 @@
import _ from 'lodash';
import { PostFrameUpdateType } from '../types';
import { FrameEntryType, FramesType, MoveLandedType, ConversionType, PlayerIndexedType } from './common';
import { isDamaged, isGrabbed, calcDamageTaken, isInControl, didLoseStock, Timers } from './common';
import { StatComputer } from './stats';
import _ from "lodash";
import { PostFrameUpdateType } from "../types";
import { FrameEntryType, FramesType, MoveLandedType, ConversionType, PlayerIndexedType } from "./common";
import { isDamaged, isGrabbed, calcDamageTaken, isInControl, didLoseStock, Timers } from "./common";
import { StatComputer } from "./stats";
interface PlayerConversionState {
conversion: ConversionType | null;
@@ -57,13 +57,13 @@ export class ConversionComputer implements StatComputer<ConversionType[]> {
private _populateConversionTypes(): void {
// Post-processing step: set the openingTypes
const conversionsToHandle = _.filter(this.conversions, (conversion) => {
return conversion.openingType === 'unknown';
return conversion.openingType === "unknown";
});
// Group new conversions by startTime and sort
const sortedConversions: ConversionType[][] = _.chain(conversionsToHandle)
.groupBy('startFrame')
.orderBy((conversions) => _.get(conversions, [0, 'startFrame']))
.groupBy("startFrame")
.orderBy((conversions) => _.get(conversions, [0, "startFrame"]))
.value();
// Set the opening types on the conversions we need to handle
@@ -75,14 +75,14 @@ export class ConversionComputer implements StatComputer<ConversionType[]> {
if (isTrade) {
// If trade, just short-circuit
conversion.openingType = 'trade';
conversion.openingType = "trade";
return;
}
// If not trade, check the opponent endFrame
const oppEndFrame = this.metadata.lastEndFrameByOppIdx[conversion.opponentIndex];
const isCounterAttack = oppEndFrame && oppEndFrame > conversion.startFrame;
conversion.openingType = isCounterAttack ? 'counter-attack' : 'neutral-win';
conversion.openingType = isCounterAttack ? "counter-attack" : "neutral-win";
});
});
}
@@ -98,11 +98,11 @@ function handleConversionCompute(
const playerFrame: PostFrameUpdateType = frame.players[indices.playerIndex].post;
// FIXME: use type PostFrameUpdateType instead of any
// This is because the default value {} should not be casted as a type of PostFrameUpdateType
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.playerIndex, 'post'], {});
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.playerIndex, "post"], {});
const opponentFrame: PostFrameUpdateType = frame.players[indices.opponentIndex].post;
// FIXME: use type PostFrameUpdateType instead of any
// This is because the default value {} should not be casted as a type of PostFrameUpdateType
const prevOpponentFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.opponentIndex, 'post'], {});
const prevOpponentFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.opponentIndex, "post"], {});
const opntIsDamaged = isDamaged(opponentFrame.actionStateId);
const opntIsGrabbed = isGrabbed(opponentFrame.actionStateId);
@@ -136,7 +136,7 @@ function handleConversionCompute(
endPercent: null,
moves: [],
didKill: false,
openingType: 'unknown', // Will be updated later
openingType: "unknown", // Will be updated later
};
conversions.push(state.conversion);

View File

@@ -1,9 +1,9 @@
export * from './common';
export * from "./common";
export { ActionsComputer } from './actions';
export { ConversionComputer } from './conversions';
export { ComboComputer } from './combos';
export { StockComputer } from './stocks';
export { InputComputer } from './inputs';
export { Stats, StatComputer, StatOptions } from './stats';
export { generateOverallStats } from './overall';
export { ActionsComputer } from "./actions";
export { ConversionComputer } from "./conversions";
export { ComboComputer } from "./combos";
export { StockComputer } from "./stocks";
export { InputComputer } from "./inputs";
export { Stats, StatComputer, StatOptions } from "./stats";
export { generateOverallStats } from "./overall";

View File

@@ -1,7 +1,7 @@
import _ from 'lodash';
import { FramesType, FrameEntryType, Frames, PlayerIndexedType } from './common';
import _ from "lodash";
import { FramesType, FrameEntryType, Frames, PlayerIndexedType } from "./common";
import { StatComputer } from './stats';
import { StatComputer } from "./stats";
enum JoystickRegion {
DZ = 0,
@@ -58,7 +58,7 @@ function handleInputCompute(
const playerFrame = frame.players[indices.playerIndex].pre;
// FIXME: use PreFrameUpdateType instead of any
// This is because the default value {} should not be casted as a type of PreFrameUpdateType
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.playerIndex, 'pre'], {});
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.playerIndex, "pre"], {});
if (playerFrame.frame < Frames.FIRST_PLAYABLE) {
// Don't count inputs until the game actually starts

View File

@@ -1,6 +1,6 @@
import _ from 'lodash';
import { ConversionType, PlayerIndexedType, StockType, OverallType, RatioType } from './common';
import { PlayerInput } from './inputs';
import _ from "lodash";
import { ConversionType, PlayerIndexedType, StockType, OverallType, RatioType } from "./common";
import { PlayerInput } from "./inputs";
interface ConversionsByPlayerByOpening {
[playerIndex: string]: {
@@ -15,11 +15,11 @@ export function generateOverallStats(
conversions: ConversionType[],
playableFrameCount: number,
): OverallType[] {
const inputsByPlayer = _.keyBy(inputs, 'playerIndex');
const stocksByPlayer = _.groupBy(stocks, 'playerIndex');
const conversionsByPlayer = _.groupBy(conversions, 'playerIndex');
const inputsByPlayer = _.keyBy(inputs, "playerIndex");
const stocksByPlayer = _.groupBy(stocks, "playerIndex");
const conversionsByPlayer = _.groupBy(conversions, "playerIndex");
const conversionsByPlayerByOpening: ConversionsByPlayerByOpening = _.mapValues(conversionsByPlayer, (conversions) =>
_.groupBy(conversions, 'openingType'),
_.groupBy(conversions, "openingType"),
);
const gameMinutes = playableFrameCount / 3600;
@@ -28,15 +28,15 @@ export function generateOverallStats(
const playerIndex = indices.playerIndex;
const opponentIndex = indices.opponentIndex;
const inputCount = _.get(inputsByPlayer, [playerIndex, 'inputCount']) || 0;
const inputCount = _.get(inputsByPlayer, [playerIndex, "inputCount"]) || 0;
const conversions = _.get(conversionsByPlayer, playerIndex) || [];
const successfulConversions = conversions.filter((conversion) => conversion.moves.length > 1);
const opponentStocks = _.get(stocksByPlayer, opponentIndex) || [];
const opponentEndedStocks = _.filter(opponentStocks, 'endFrame');
const opponentEndedStocks = _.filter(opponentStocks, "endFrame");
const conversionCount = conversions.length;
const successfulConversionCount = successfulConversions.length;
const totalDamage = _.sumBy(opponentStocks, 'currentPercent') || 0;
const totalDamage = _.sumBy(opponentStocks, "currentPercent") || 0;
const killCount = opponentEndedStocks.length;
return {
@@ -51,8 +51,8 @@ export function generateOverallStats(
inputsPerMinute: getRatio(inputCount, gameMinutes),
openingsPerKill: getRatio(conversionCount, killCount),
damagePerOpening: getRatio(totalDamage, conversionCount),
neutralWinRatio: getOpeningRatio(conversionsByPlayerByOpening, playerIndex, opponentIndex, 'neutral-win'),
counterHitRatio: getOpeningRatio(conversionsByPlayerByOpening, playerIndex, opponentIndex, 'counter-attack'),
neutralWinRatio: getOpeningRatio(conversionsByPlayerByOpening, playerIndex, opponentIndex, "neutral-win"),
counterHitRatio: getOpeningRatio(conversionsByPlayerByOpening, playerIndex, opponentIndex, "counter-attack"),
beneficialTradeRatio: getBeneficialTradeRatio(conversionsByPlayerByOpening, playerIndex, opponentIndex),
};
});
@@ -86,8 +86,8 @@ function getBeneficialTradeRatio(
playerIndex: number,
opponentIndex: number,
): RatioType {
const playerTrades = _.get(conversionsByPlayerByOpening, [playerIndex, 'trade']) || [];
const opponentTrades = _.get(conversionsByPlayerByOpening, [opponentIndex, 'trade']) || [];
const playerTrades = _.get(conversionsByPlayerByOpening, [playerIndex, "trade"]) || [];
const opponentTrades = _.get(conversionsByPlayerByOpening, [opponentIndex, "trade"]) || [];
const benefitsPlayer = [];

View File

@@ -1,6 +1,6 @@
import _ from 'lodash';
import _ from "lodash";
import { FrameEntryType, PlayerIndexedType, Frames, FramesType } from './common';
import { FrameEntryType, PlayerIndexedType, Frames, FramesType } from "./common";
export interface StatComputer<T> {
setPlayerPermutations(indices: PlayerIndexedType[]): void;
@@ -68,8 +68,8 @@ function isCompletedFrame(playerPermutations: PlayerIndexedType[], frame: FrameE
// follower frames are not used for any stat calculations so this doesn't matter
// for our purposes.
const indices = _.first(playerPermutations);
const playerPostFrame = _.get(frame, ['players', indices.playerIndex, 'post']);
const oppPostFrame = _.get(frame, ['players', indices.opponentIndex, 'post']);
const playerPostFrame = _.get(frame, ["players", indices.playerIndex, "post"]);
const oppPostFrame = _.get(frame, ["players", indices.opponentIndex, "post"]);
return Boolean(playerPostFrame && oppPostFrame);
}

View File

@@ -1,8 +1,8 @@
// @flow
import _ from 'lodash';
import _ from "lodash";
import { FrameEntryType, FramesType, isDead, didLoseStock, PlayerIndexedType, StockType } from './common';
import { StatComputer } from './stats';
import { FrameEntryType, FramesType, isDead, didLoseStock, PlayerIndexedType, StockType } from "./common";
import { StatComputer } from "./stats";
interface StockState {
stock?: StockType | null;
@@ -44,7 +44,7 @@ function handleStockCompute(
): void {
const playerFrame = frame.players[indices.playerIndex].post;
// FIXME: use PostFrameUpdateType instead of any
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, 'players', indices.playerIndex, 'post'], {});
const prevPlayerFrame: any = _.get(frames, [playerFrame.frame - 1, "players", indices.playerIndex, "post"], {});
// If there is currently no active stock, wait until the player is no longer spawning.
// Once the player is no longer spawning, start the stock

View File

@@ -1,4 +1,4 @@
import _ from 'lodash';
import _ from "lodash";
export function toHalfwidth(str: string): string {
// Code reference from https://github.com/sampathsris/ascii-fullwidth-halfwidth-convert

View File

@@ -1,9 +1,9 @@
import { forEach } from 'lodash';
import fs, { WriteStream } from 'fs';
import moment, { Moment } from 'moment';
import { Writable, WritableOptions } from 'stream';
import { forEach } from "lodash";
import fs, { WriteStream } from "fs";
import moment, { Moment } from "moment";
import { Writable, WritableOptions } from "stream";
const DEFAULT_NICKNAME = 'unknown';
const DEFAULT_NICKNAME = "unknown";
export interface SlpFileMetadata {
startTime: Moment;
@@ -42,10 +42,10 @@ export class SlpFile extends Writable {
};
this._initializeNewGame(this.filePath);
this.on('finish', () => {
this.on("finish", () => {
// Write bytes written
const fd = fs.openSync(this.filePath, 'r+');
(fs as any).writeSync(fd, createUInt32Buffer(this.rawDataLength), 0, 'binary', 11);
const fd = fs.openSync(this.filePath, "r+");
(fs as any).writeSync(fd, createUInt32Buffer(this.rawDataLength), 0, "binary", 11);
fs.closeSync(fd);
});
}
@@ -71,7 +71,7 @@ export class SlpFile extends Writable {
}
public _write(chunk: Uint8Array, encoding: string, callback: (error?: Error | null) => void): void {
if (encoding !== 'buffer') {
if (encoding !== "buffer") {
throw new Error(`Unsupported stream encoding. Expected 'buffer' got '${encoding}'.`);
}
this.fileStream.write(chunk);
@@ -81,28 +81,28 @@ export class SlpFile extends Writable {
private _initializeNewGame(filePath: string): void {
this.fileStream = fs.createWriteStream(filePath, {
encoding: 'binary',
encoding: "binary",
});
const header = Buffer.concat([
Buffer.from('{U'),
Buffer.from("{U"),
Buffer.from([3]),
Buffer.from('raw[$U#l'),
Buffer.from("raw[$U#l"),
Buffer.from([0, 0, 0, 0]),
]);
this.fileStream.write(header);
}
public _final(callback: (error?: Error | null) => void): void {
let footer = Buffer.concat([Buffer.from('U'), Buffer.from([8]), Buffer.from('metadata{')]);
let footer = Buffer.concat([Buffer.from("U"), Buffer.from([8]), Buffer.from("metadata{")]);
// Write game start time
const startTimeStr = this.metadata.startTime.toISOString();
footer = Buffer.concat([
footer,
Buffer.from('U'),
Buffer.from("U"),
Buffer.from([7]),
Buffer.from('startAtSU'),
Buffer.from("startAtSU"),
Buffer.from([startTimeStr.length]),
Buffer.from(startTimeStr),
]);
@@ -112,9 +112,9 @@ export class SlpFile extends Writable {
const lastFrame = this.metadata.lastFrame;
footer = Buffer.concat([
footer,
Buffer.from('U'),
Buffer.from("U"),
Buffer.from([9]),
Buffer.from('lastFramel'),
Buffer.from("lastFramel"),
createInt32Buffer(lastFrame),
]);
@@ -122,29 +122,29 @@ export class SlpFile extends Writable {
const consoleNick = this.metadata.consoleNickname || DEFAULT_NICKNAME;
footer = Buffer.concat([
footer,
Buffer.from('U'),
Buffer.from("U"),
Buffer.from([11]),
Buffer.from('consoleNickSU'),
Buffer.from("consoleNickSU"),
Buffer.from([consoleNick.length]),
Buffer.from(consoleNick),
]);
// Start writting player specific data
footer = Buffer.concat([footer, Buffer.from('U'), Buffer.from([7]), Buffer.from('players{')]);
footer = Buffer.concat([footer, Buffer.from("U"), Buffer.from([7]), Buffer.from("players{")]);
const players = this.metadata.players;
forEach(players, (player, index) => {
// Start player obj with index being the player index
footer = Buffer.concat([footer, Buffer.from('U'), Buffer.from([index.length]), Buffer.from(`${index}{`)]);
footer = Buffer.concat([footer, Buffer.from("U"), Buffer.from([index.length]), Buffer.from(`${index}{`)]);
// Start characters key for this player
footer = Buffer.concat([footer, Buffer.from('U'), Buffer.from([10]), Buffer.from('characters{')]);
footer = Buffer.concat([footer, Buffer.from("U"), Buffer.from([10]), Buffer.from("characters{")]);
// Write character usage
forEach(player.characterUsage, (usage, internalId) => {
// Write this character
footer = Buffer.concat([
footer,
Buffer.from('U'),
Buffer.from("U"),
Buffer.from([internalId.length]),
Buffer.from(`${internalId}l`),
createUInt32Buffer(usage),
@@ -152,24 +152,24 @@ export class SlpFile extends Writable {
});
// Close characters and player
footer = Buffer.concat([footer, Buffer.from('}}')]);
footer = Buffer.concat([footer, Buffer.from("}}")]);
});
// Close players
footer = Buffer.concat([footer, Buffer.from('}')]);
footer = Buffer.concat([footer, Buffer.from("}")]);
// Write played on
footer = Buffer.concat([
footer,
Buffer.from('U'),
Buffer.from("U"),
Buffer.from([8]),
Buffer.from('playedOnSU'),
Buffer.from("playedOnSU"),
Buffer.from([7]),
Buffer.from('network'),
Buffer.from("network"),
]);
// Close metadata and file
footer = Buffer.concat([footer, Buffer.from('}}')]);
footer = Buffer.concat([footer, Buffer.from("}}")]);
// End the stream
this.fileStream.write(footer, callback);

View File

@@ -1,5 +1,5 @@
import _ from 'lodash';
import semver from 'semver';
import _ from "lodash";
import semver from "semver";
import {
PostFrameUpdateType,
@@ -10,17 +10,17 @@ import {
ItemUpdateType,
FrameBookendType,
GameMode,
} from '../types';
import { FramesType, FrameEntryType, Frames } from '../stats';
import { EventEmitter } from 'events';
} from "../types";
import { FramesType, FrameEntryType, Frames } from "../stats";
import { EventEmitter } from "events";
export const MAX_ROLLBACK_FRAMES = 7;
export enum SlpParserEvent {
SETTINGS = 'settings',
END = 'end',
FRAME = 'frame', // Emitted for every frame
FINALIZED_FRAME = 'finalized-frame', // Emitted for only finalized frames
SETTINGS = "settings",
END = "end",
FRAME = "frame", // Emitted for every frame
FINALIZED_FRAME = "finalized-frame", // Emitted for only finalized frames
}
export class SlpParser extends EventEmitter {
@@ -122,7 +122,7 @@ export class SlpParser extends EventEmitter {
// Check to see if the file was created after the sheik fix so we know
// we don't have to process the first frame of the game for the full settings
if (semver.gte(payload.slpVersion, '1.6.0')) {
if (semver.gte(payload.slpVersion, "1.6.0")) {
this._completeSettings();
}
}
@@ -135,7 +135,7 @@ export class SlpParser extends EventEmitter {
// Finish calculating settings
if (payload.frame <= Frames.FIRST) {
const playerIndex = payload.playerIndex;
const playersByIndex = _.keyBy(this.settings.players, 'playerIndex');
const playersByIndex = _.keyBy(this.settings.players, "playerIndex");
switch (payload.internalCharacterId) {
case 0x7:
@@ -153,35 +153,35 @@ export class SlpParser extends EventEmitter {
private _handleFrameUpdate(command: Command, payload: PreFrameUpdateType | PostFrameUpdateType): void {
payload = payload as PostFrameUpdateType;
const location = command === Command.PRE_FRAME_UPDATE ? 'pre' : 'post';
const field = payload.isFollower ? 'followers' : 'players';
const location = command === Command.PRE_FRAME_UPDATE ? "pre" : "post";
const field = payload.isFollower ? "followers" : "players";
this.latestFrameIndex = payload.frame;
_.set(this.frames, [payload.frame, field, payload.playerIndex, location], payload);
_.set(this.frames, [payload.frame, 'frame'], payload.frame);
_.set(this.frames, [payload.frame, "frame"], payload.frame);
// If file is from before frame bookending, add frame to stats computer here. Does a little
// more processing than necessary, but it works
const settings = this.getSettings();
if (!settings || semver.lte(settings.slpVersion, '2.2.0')) {
if (!settings || semver.lte(settings.slpVersion, "2.2.0")) {
this.emit(SlpParserEvent.FRAME, this.frames[payload.frame]);
// Finalize the previous frame since no bookending exists
this._finalizeFrames(payload.frame - 1);
} else {
_.set(this.frames, [payload.frame, 'isTransferComplete'], false);
_.set(this.frames, [payload.frame, "isTransferComplete"], false);
}
}
private _handleItemUpdate(payload: ItemUpdateType): void {
const items = _.get(this.frames, [payload.frame, 'items'], []);
const items = _.get(this.frames, [payload.frame, "items"], []);
items.push(payload);
// Set items with newest
_.set(this.frames, [payload.frame, 'items'], items);
_.set(this.frames, [payload.frame, "items"], items);
}
private _handleFrameBookend(payload: FrameBookendType): void {
const { frame, latestFinalizedFrame } = payload;
_.set(this.frames, [frame, 'isTransferComplete'], true);
_.set(this.frames, [frame, "isTransferComplete"], true);
// Fire off a normal frame event
this.emit(SlpParserEvent.FRAME, this.frames[frame]);

View File

@@ -1,14 +1,14 @@
import _ from 'lodash';
import fs from 'fs';
import iconv from 'iconv-lite';
import { decode } from '@shelacek/ubjson';
import _ from "lodash";
import fs from "fs";
import iconv from "iconv-lite";
import { decode } from "@shelacek/ubjson";
import { toHalfwidth } from './fullwidth';
import { Command, EventCallbackFunc, EventPayloadTypes, MetadataType, PlayerType } from '../types';
import { toHalfwidth } from "./fullwidth";
import { Command, EventCallbackFunc, EventPayloadTypes, MetadataType, PlayerType } from "../types";
export enum SlpInputSource {
BUFFER = 'buffer',
FILE = 'file',
BUFFER = "buffer",
FILE = "file",
}
export interface SlpReadInput {
@@ -43,7 +43,7 @@ export interface SlpBufferSourceRef {
function getRef(input: SlpReadInput): SlpRefType {
switch (input.source) {
case SlpInputSource.FILE:
const fd = fs.openSync(input.filePath, 'r');
const fd = fs.openSync(input.filePath, "r");
return {
source: input.source,
fileDescriptor: fd,
@@ -54,7 +54,7 @@ function getRef(input: SlpReadInput): SlpRefType {
buffer: input.buffer,
} as SlpBufferSourceRef;
default:
throw new Error('Source type not supported');
throw new Error("Source type not supported");
}
}
@@ -65,7 +65,7 @@ function readRef(ref: SlpRefType, buffer: Uint8Array, offset: number, length: nu
case SlpInputSource.BUFFER:
return (ref as SlpBufferSourceRef).buffer.copy(buffer, offset, position, position + length);
default:
throw new Error('Source type not supported');
throw new Error("Source type not supported");
}
}
@@ -77,7 +77,7 @@ function getLenRef(ref: SlpRefType): number {
case SlpInputSource.BUFFER:
return (ref as SlpBufferSourceRef).buffer.length;
default:
throw new Error('Source type not supported');
throw new Error("Source type not supported");
}
}
@@ -120,7 +120,7 @@ function getRawDataPosition(ref: SlpRefType): number {
return 0;
}
if (buffer[0] !== '{'.charCodeAt(0)) {
if (buffer[0] !== "{".charCodeAt(0)) {
return 0; // return error?
}
@@ -244,13 +244,13 @@ export function parseMessage(command: Command, payload: Uint8Array): EventPayloa
const cfOffset = playerIndex * 0x8;
const dashback = readUint32(view, 0x141 + cfOffset);
const shieldDrop = readUint32(view, 0x145 + cfOffset);
let cfOption = 'None';
let cfOption = "None";
if (dashback !== shieldDrop) {
cfOption = 'Mixed';
cfOption = "Mixed";
} else if (dashback === 1) {
cfOption = 'UCF';
cfOption = "UCF";
} else if (dashback === 2) {
cfOption = 'Dween';
cfOption = "Dween";
}
// Nametag stuff
@@ -259,8 +259,8 @@ export function parseMessage(command: Command, payload: Uint8Array): EventPayloa
const nametagBuf = payload.slice(nametagStart, nametagStart + 16);
const nametag = toHalfwidth(
iconv
.decode(nametagBuf as Buffer, 'Shift_JIS')
.split('\0')
.decode(nametagBuf as Buffer, "Shift_JIS")
.split("\0")
.shift(),
);

View File

@@ -1,11 +1,11 @@
import { Writable, WritableOptions } from 'stream';
import { Command, EventPayloadTypes } from '../types';
import { parseMessage } from './slpReader';
import { NETWORK_MESSAGE } from '../console/connection';
import { Writable, WritableOptions } from "stream";
import { Command, EventPayloadTypes } from "../types";
import { parseMessage } from "./slpReader";
import { NETWORK_MESSAGE } from "../console/connection";
export enum SlpStreamMode {
AUTO = 'AUTO', // Always reading data, but errors on invalid command
MANUAL = 'MANUAL', // Stops parsing inputs after a valid game end command, requires manual restarting
AUTO = "AUTO", // Always reading data, but errors on invalid command
MANUAL = "MANUAL", // Stops parsing inputs after a valid game end command, requires manual restarting
}
const defaultSettings = {
@@ -28,8 +28,8 @@ export interface SlpRawEventPayload {
}
export enum SlpStreamEvent {
RAW = 'slp-raw',
COMMAND = 'slp-command',
RAW = "slp-raw",
COMMAND = "slp-command",
}
/**
@@ -67,7 +67,7 @@ export class SlpStream extends Writable {
}
public _write(newData: Buffer, encoding: string, callback: (error?: Error | null, data?: any) => void): void {
if (encoding !== 'buffer') {
if (encoding !== "buffer") {
throw new Error(`Unsupported stream encoding. Expected 'buffer' got '${encoding}'.`);
}

View File

@@ -1,19 +1,19 @@
import _ from 'lodash';
import _ from "lodash";
// import path from 'path';
import fs from 'fs';
import { SlippiGame } from '../src';
import fs from "fs";
import { SlippiGame } from "../src";
it('should correctly return game settings', () => {
const game = new SlippiGame('slp/sheik_vs_ics_yoshis.slp');
it("should correctly return game settings", () => {
const game = new SlippiGame("slp/sheik_vs_ics_yoshis.slp");
const settings = game.getSettings();
expect(settings.stageId).toBe(8);
expect(_.first(settings.players).characterId).toBe(0x13);
expect(_.last(settings.players).characterId).toBe(0xe);
expect(settings.slpVersion).toBe('0.1.0');
expect(settings.slpVersion).toBe("0.1.0");
});
it('should correctly return stats', () => {
const game = new SlippiGame('slp/test.slp');
it("should correctly return stats", () => {
const game = new SlippiGame("slp/test.slp");
const stats = game.getStats();
expect(stats.lastFrame).toBe(3694);
@@ -39,56 +39,56 @@ it('should correctly return stats', () => {
expect(stats.overall[0].inputCount).toBe(494);
});
it('should correctly return metadata', () => {
const game = new SlippiGame('slp/test.slp');
it("should correctly return metadata", () => {
const game = new SlippiGame("slp/test.slp");
const metadata = game.getMetadata();
expect(metadata.startAt).toBe('2017-12-18T21:14:14Z');
expect(metadata.playedOn).toBe('dolphin');
expect(metadata.startAt).toBe("2017-12-18T21:14:14Z");
expect(metadata.playedOn).toBe("dolphin");
});
it('should be able to read incomplete SLP files', () => {
const game = new SlippiGame('slp/incomplete.slp');
it("should be able to read incomplete SLP files", () => {
const game = new SlippiGame("slp/incomplete.slp");
const settings = game.getSettings();
expect(settings.players.length).toBe(2);
game.getMetadata();
game.getStats();
});
it('should be able to read nametags', () => {
const game = new SlippiGame('slp/nametags.slp');
it("should be able to read nametags", () => {
const game = new SlippiGame("slp/nametags.slp");
const settings = game.getSettings();
expect(settings.players[0].nametag).toBe('AMNイ');
expect(settings.players[1].nametag).toBe('');
expect(settings.players[0].nametag).toBe("AMNイ");
expect(settings.players[1].nametag).toBe("");
const game2 = new SlippiGame('slp/nametags2.slp');
const game2 = new SlippiGame("slp/nametags2.slp");
const settings2 = game2.getSettings();
expect(settings2.players[0].nametag).toBe('A1=$');
expect(settings2.players[1].nametag).toBe('か、9@');
expect(settings2.players[0].nametag).toBe("A1=$");
expect(settings2.players[1].nametag).toBe("か、9@");
const game3 = new SlippiGame('slp/nametags3.slp');
const game3 = new SlippiGame("slp/nametags3.slp");
const settings3 = game3.getSettings();
expect(settings3.players[0].nametag).toBe('B R');
expect(settings3.players[1].nametag).toBe('. 。');
expect(settings3.players[0].nametag).toBe("B R");
expect(settings3.players[1].nametag).toBe(". 。");
});
it('should support PAL version', () => {
const palGame = new SlippiGame('slp/pal.slp');
const ntscGame = new SlippiGame('slp/ntsc.slp');
it("should support PAL version", () => {
const palGame = new SlippiGame("slp/pal.slp");
const ntscGame = new SlippiGame("slp/ntsc.slp");
expect(palGame.getSettings().isPAL).toBe(true);
expect(ntscGame.getSettings().isPAL).toBe(false);
});
it('should correctly distinguish between different controller fixes', () => {
const game = new SlippiGame('slp/controllerFixes.slp');
it("should correctly distinguish between different controller fixes", () => {
const game = new SlippiGame("slp/controllerFixes.slp");
const settings = game.getSettings();
expect(settings.players[0].controllerFix).toBe('Dween');
expect(settings.players[1].controllerFix).toBe('UCF');
expect(settings.players[2].controllerFix).toBe('None');
expect(settings.players[0].controllerFix).toBe("Dween");
expect(settings.players[1].controllerFix).toBe("UCF");
expect(settings.players[2].controllerFix).toBe("None");
});
it('should be able to support reading from a buffer input', () => {
const buf = fs.readFileSync('slp/sheik_vs_ics_yoshis.slp');
it("should be able to support reading from a buffer input", () => {
const buf = fs.readFileSync("slp/sheik_vs_ics_yoshis.slp");
const game = new SlippiGame(buf);
const settings = game.getSettings();
expect(settings.stageId).toBe(8);
@@ -96,7 +96,7 @@ it('should be able to support reading from a buffer input', () => {
expect(_.last(settings.players).characterId).toBe(0xe);
});
it.skip('should support item information extraction', () => {
it.skip("should support item information extraction", () => {
// const game = new SlippiGame("slp/itemExport.slp");
// const frames = game.getFrames();
// TODO: Add test
@@ -121,8 +121,8 @@ it.skip('should support item information extraction', () => {
// console.log(frames[429].items);
});
it('should support realtime parsing', () => {
const fullData = fs.readFileSync('slp/realtimeTest.slp');
it("should support realtime parsing", () => {
const fullData = fs.readFileSync("slp/realtimeTest.slp");
const buf = Buffer.alloc(100e6); // Allocate 100 MB of space
const game = new SlippiGame(buf);
@@ -175,7 +175,7 @@ it('should support realtime parsing', () => {
// Load metadata
copyBuf(0xa7);
data = getData();
expect(data.metadata.playedOn).toBe('network');
expect(data.metadata.playedOn).toBe("network");
});
// it('test speedReadTest', () => {

View File

@@ -1,5 +1,5 @@
import fs from 'fs';
import { Writable } from 'stream';
import fs from "fs";
import { Writable } from "stream";
import SlippiGame, {
Command,
@@ -14,11 +14,11 @@ import SlippiGame, {
FrameEntryType,
MAX_ROLLBACK_FRAMES,
GameMode,
} from '../src';
} from "../src";
describe('when reading last finalised frame from SlpStream', () => {
it('should never decrease', async () => {
const testFile = 'slp/finalizedFrame.slp';
describe("when reading last finalised frame from SlpStream", () => {
it("should never decrease", async () => {
const testFile = "slp/finalizedFrame.slp";
const stream = new SlpStream({
mode: SlpStreamMode.MANUAL,
});
@@ -51,9 +51,9 @@ describe('when reading last finalised frame from SlpStream', () => {
});
});
describe('when reading finalised frames from SlpParser', () => {
it('should support older SLP files without frame bookend', async () => {
const testFile = 'slp/sheik_vs_ics_yoshis.slp';
describe("when reading finalised frames from SlpParser", () => {
it("should support older SLP files without frame bookend", async () => {
const testFile = "slp/sheik_vs_ics_yoshis.slp";
const stream = new SlpStream({
mode: SlpStreamMode.MANUAL,
});
@@ -87,8 +87,8 @@ describe('when reading finalised frames from SlpParser', () => {
expect(lastFrame).toEqual(lastFinalizedFrame);
});
it('should only increase', async () => {
const testFile = 'slp/finalizedFrame.slp';
it("should only increase", async () => {
const testFile = "slp/finalizedFrame.slp";
const stream = new SlpStream({
mode: SlpStreamMode.MANUAL,
});
@@ -123,10 +123,10 @@ describe('when reading finalised frames from SlpParser', () => {
const pipeFileContents = async (filename: string, destination: Writable, options?: any): Promise<void> => {
return new Promise((resolve): void => {
const readStream = fs.createReadStream(filename);
readStream.on('open', () => {
readStream.on("open", () => {
readStream.pipe(destination, options);
});
readStream.on('close', () => {
readStream.on("close", () => {
resolve();
});
});