mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-30 20:56:58 -05:00
264 lines
7.8 KiB
JavaScript
Executable File
264 lines
7.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
// Before running, ensure that the Typescript files have been compiled.
|
|
//
|
|
// Simply doing `require('../build')` here doesn't work because the `replace`
|
|
// step of the build is asynchronous and we can't wait for it to finish easily
|
|
// unless we shell out and use `execSync`. However, the heuristic of simply
|
|
// checking for the presence of './.sim-dist/dex' to determine whether a build
|
|
// is required is somewhat risky as it only is valid from a clean repository -
|
|
// if you make edits or have previous build artifacts lying around, this
|
|
// script could potentially be missing additional sources or the compiled output
|
|
// may be out of date.
|
|
//
|
|
// We're OK with risking being stale here unless we're starting the server
|
|
// because we want to keep this script as fast as possible to be usable as a way
|
|
// of interfacing with the simulator from non-JS languages. Otherwise we error
|
|
// on the side of caution and run `node build` to ensure we're always running
|
|
// with the latest code.
|
|
var built = false;
|
|
function build() {
|
|
require('child_process').execSync('node build', {stdio: 'inherit', cwd: __dirname});
|
|
built = true;
|
|
}
|
|
|
|
function readTeam(stream) {
|
|
return stream.readLine().then(line => {
|
|
if (line.startsWith('[') || line.includes('|')) return line;
|
|
return stream.readAll().then(all => (line + '\n' + all));
|
|
});
|
|
}
|
|
|
|
function registerTSNode() {
|
|
require('ts-node').register({project: './tsconfig.json', files: true, transpileOnly: true, transpiler: 'ts-node/transpilers/swc-experimental'});
|
|
}
|
|
|
|
// enable require()ing TypeScript files
|
|
function setupTSNode() {
|
|
try {
|
|
registerTSNode();
|
|
} catch (e) {
|
|
console.log(`Installing dependencies...`);
|
|
require('child_process').execSync('npm install --production', {stdio: 'inherit'});
|
|
registerTSNode();
|
|
}
|
|
}
|
|
|
|
function sucraseBuild() {
|
|
try {
|
|
require.resolve('./.sim-dist/dex');
|
|
} catch (err) {
|
|
if (err.code !== 'MODULE_NOT_FOUND') throw err; // should never happen
|
|
build();
|
|
}
|
|
}
|
|
|
|
if (!process.argv[2] || /^[0-9]+$/.test(process.argv[2])) {
|
|
// Start the server.
|
|
//
|
|
// The port the server should host on can be passed using the second argument
|
|
// when launching with this file the same way app.js normally allows, e.g. to
|
|
// host on port 9000:
|
|
// $ ./pokemon-showdown 9000
|
|
setupTSNode();
|
|
require('module')._load('./server', module, true);
|
|
} else switch (process.argv[2]) {
|
|
case 'help':
|
|
case 'h':
|
|
case '?':
|
|
case '-h':
|
|
case '--help':
|
|
case '-?':
|
|
console.log('pokemon-showdown start [--skip-build] [PORT]');
|
|
console.log('');
|
|
console.log(' Starts a PS server on the specified port');
|
|
console.log(' (Defaults to the port setting in config/config.js)');
|
|
console.log(' (The port setting in config/config.js defaults to 8000)');
|
|
console.log('');
|
|
console.log('pokemon-showdown generate-team [FORMAT-ID [RANDOM-SEED]]');
|
|
console.log('');
|
|
console.log(' Generates a random team, and writes it to stdout in packed team format');
|
|
console.log(' (Format defaults to "gen7randombattle")');
|
|
console.log('');
|
|
console.log('pokemon-showdown validate-team [FORMAT-ID]');
|
|
console.log('');
|
|
console.log(' Reads a team from stdin, and validates it');
|
|
console.log(' If valid: exits with code 0');
|
|
console.log(' If invalid: writes errors to stderr, exits with code 1');
|
|
console.log('');
|
|
console.log('pokemon-showdown simulate-battle');
|
|
console.log('');
|
|
console.log(' Simulates a battle, taking input to stdin and writing output to stdout');
|
|
console.log(' Protocol is documented in ./.sim-dist/README.md');
|
|
console.log('');
|
|
console.log('pokemon-showdown json-team');
|
|
console.log('');
|
|
console.log(' Reads a team in any format from stdin, writes the unpacked JSON to stdout');
|
|
console.log('');
|
|
console.log('pokemon-showdown pack-team');
|
|
console.log('');
|
|
console.log(' Reads a team in any format from stdin, writes the packed team to stdout');
|
|
console.log('');
|
|
console.log('pokemon-showdown export-team');
|
|
console.log('');
|
|
console.log(' Reads a team in any format from stdin, writes the exported (human-readable) team to stdout');
|
|
console.log('');
|
|
console.log('pokemon-showdown help');
|
|
console.log('');
|
|
console.log(' Displays this reference');
|
|
break;
|
|
case 'start':
|
|
{
|
|
process.argv.splice(2, 1);
|
|
setupTSNode();
|
|
require('module')._load('./server', module, true);
|
|
break;
|
|
}
|
|
case 'generate-team':
|
|
{
|
|
sucraseBuild();
|
|
var Teams = require('./.sim-dist/teams').Teams;
|
|
var seed = process.argv[4] ? process.argv[4].split(',').map(Number) : undefined;
|
|
console.log(Teams.pack(Teams.generate(process.argv[3], {seed})));
|
|
}
|
|
break;
|
|
case 'validate-team':
|
|
{
|
|
sucraseBuild();
|
|
var Teams = require('./.sim-dist/teams').Teams;
|
|
var TeamValidator = require('./.sim-dist/team-validator').TeamValidator;
|
|
var validator = TeamValidator.get(process.argv[3]);
|
|
var Streams = require('./.lib-dist/streams');
|
|
var stdin = Streams.stdin();
|
|
|
|
readTeam(stdin).then(function (textTeam) {
|
|
try {
|
|
var team = Teams.import(textTeam);
|
|
var result = validator.validateTeam(team);
|
|
if (result) {
|
|
console.error(result.join('\n'));
|
|
process.exit(1);
|
|
}
|
|
process.exit(0);
|
|
} catch (e) {
|
|
console.error(e);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case 'simulate-battle':
|
|
{
|
|
sucraseBuild();
|
|
var BattleTextStream = require('./.sim-dist/battle-stream').BattleTextStream;
|
|
var Streams = require('./.lib-dist/streams');
|
|
var stdin = Streams.stdin();
|
|
var stdout = Streams.stdout();
|
|
|
|
var args = process.argv.slice(3);
|
|
|
|
var options = args.flatMap(function (arg) {
|
|
if (arg.charAt(0) !== '-') {
|
|
if (arg) console.error("Invalid parameter: " + arg);
|
|
return [];
|
|
} else if (arg.charAt(1) === '-') {
|
|
return arg.slice(2);
|
|
} else {
|
|
return Array.from(arg.slice(1));
|
|
}
|
|
});
|
|
|
|
var debug = false;
|
|
var replay = false;
|
|
var spectate = false;
|
|
for (var i = 0; i < options.length; i++) {
|
|
switch (options[i]) {
|
|
case 'debug': case 'D':
|
|
debug = true;
|
|
break;
|
|
case 'replay': case 'R':
|
|
replay = true;
|
|
break;
|
|
case 'spectate': case 'spectator': case 'S':
|
|
replay = true;
|
|
spectate = true;
|
|
break;
|
|
default:
|
|
console.error("Invalid option: " + options[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
var battleStream = new BattleTextStream({
|
|
noCatch: true,
|
|
debug: debug,
|
|
replay: spectate ? 'spectator' : replay,
|
|
});
|
|
stdin.pipeTo(battleStream);
|
|
battleStream.pipeTo(stdout);
|
|
}
|
|
break;
|
|
case 'unpack-team':
|
|
case 'json-team':
|
|
{
|
|
sucraseBuild();
|
|
var Teams = require('./.sim-dist/teams').Teams;
|
|
var Streams = require('./.lib-dist/streams');
|
|
var stdin = Streams.stdin();
|
|
|
|
readTeam(stdin).then(function (team) {
|
|
try {
|
|
var unpackedTeam = Teams.unpack(Teams.import(team));
|
|
console.log(JSON.stringify(unpackedTeam));
|
|
process.exit(0);
|
|
} catch (e) {
|
|
console.error(e);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case 'pack-team':
|
|
{
|
|
sucraseBuild();
|
|
var Teams = require('./.sim-dist/teams').Teams;
|
|
var Streams = require('./.lib-dist/streams');
|
|
var stdin = Streams.stdin();
|
|
|
|
readTeam(stdin).then(function (team) {
|
|
try {
|
|
var packedTeam = Teams.pack(Teams.import(team));
|
|
console.log(packedTeam);
|
|
process.exit(0);
|
|
} catch (e) {
|
|
console.error(e);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case 'export-team':
|
|
{
|
|
sucraseBuild();
|
|
var Teams = require('./.sim-dist/teams').Teams;
|
|
var Streams = require('./.lib-dist/streams');
|
|
var stdin = Streams.stdin();
|
|
|
|
readTeam(stdin).then(function (team) {
|
|
try {
|
|
var exportedTeam = Teams.export(Teams.import(team));
|
|
console.log(exportedTeam);
|
|
process.exit(0);
|
|
} catch (e) {
|
|
console.error(e);
|
|
process.exit(1);
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
default:
|
|
console.error('Unrecognized command: ' + process.argv[2]);
|
|
console.error('Use `pokemon-showdown help` for help');
|
|
process.exit(1);
|
|
}
|