├── .gitignore ├── logo.png ├── resources ├── demo.nes ├── d1.svg ├── d2.svg ├── d0.svg ├── rom.svg └── anes.svg ├── view ├── img │ ├── alipay.png │ ├── keyboard.png │ └── wechat.png ├── vscode.call.js ├── controller.js ├── index.html └── main.js ├── .vscodeignore ├── .vscode ├── extensions.json └── launch.json ├── jsconfig.json ├── CHANGELOG.md ├── README.en.md ├── test ├── suite │ ├── extension.test.js │ └── index.js └── runTest.js ├── download.js ├── .eslintrc.json ├── README.md ├── test.js ├── vsc-extension-quickstart.md ├── romRemoteTree.js ├── fileUtil.js ├── package.json ├── romLocalTree.js └── extension.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode-test/ 3 | *.vsix 4 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamedilong/anes/HEAD/logo.png -------------------------------------------------------------------------------- /resources/demo.nes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamedilong/anes/HEAD/resources/demo.nes -------------------------------------------------------------------------------- /view/img/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamedilong/anes/HEAD/view/img/alipay.png -------------------------------------------------------------------------------- /view/img/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamedilong/anes/HEAD/view/img/keyboard.png -------------------------------------------------------------------------------- /view/img/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gamedilong/anes/HEAD/view/img/wechat.png -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | vsc-extension-quickstart.md 6 | **/jsconfig.json 7 | **/*.map 8 | **/.eslintrc.json 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "checkJs": false, /* Typecheck .js files. */ 6 | "lib": [ 7 | "es6" 8 | ] 9 | }, 10 | "exclude": [ 11 | "node_modules" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "anes" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # anes README 2 | 3 | ANES is a vscode nes game plugin 4 | 5 | # Issues 6 | 7 | Currently, the extension is in the very initial phase. If you find any bug or have any suggestion/feature request, please submit the issues to the GitHub Repo. Or you can send email to 1104238614@qq.com. -------------------------------------------------------------------------------- /test/suite/extension.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | const vscode = require('vscode'); 6 | // const myExtension = require('../extension'); 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /download.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | var fs = require("fs"); 3 | 4 | 5 | function download(url, filePath, callback){ 6 | let stream = fs.createWriteStream(filePath); 7 | request({url:url, timeout:10000}).pipe(stream).on("close", function (err) { 8 | console.log("文件[" + filePath + "]下载完毕"); 9 | callback(err); 10 | }); 11 | } 12 | 13 | 14 | // download('https://github.com/gamedilong/anes-repository/archive/master.zip','master.zip'); 15 | 16 | module.exports = { 17 | download 18 | } 19 | 20 | -------------------------------------------------------------------------------- /resources/d1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": false, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": 2018, 11 | "ecmaFeatures": { 12 | "jsx": true 13 | }, 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "no-const-assign": "warn", 18 | "no-this-before-super": "warn", 19 | "no-undef": "warn", 20 | "no-unreachable": "warn", 21 | "no-unused-vars": "warn", 22 | "constructor-super": "warn", 23 | "valid-typeof": "warn" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 小霸王 2 | 3 | 小霸王是一款基于vscode的nes游戏插件,能让你在紧张的开发之余在vscode里发松身心。通过劳逸结合,提升开发效率。 4 | # 功能 5 | ## 1. 本地仓库 6 | * 可以通过local菜单上的添加按钮添加本地nes rom文件。添加完毕后,会在local列表显示,点击即可开始游戏。 7 | * 本地仓库列表还支持 右键菜单 改名,删除功能 8 | 9 | ## 2.远程仓库 10 | * 选择想要玩的游戏,右键菜单下载。下载完成后,会加载到local菜单。点击即可完。 11 | 12 | * 远程仓库通过github维护,会不定时的更新一些新的游戏。可以通过remote上的refresh刷新按钮同步。 13 | 14 | * 远程rom仓库配置地址 https://github.com/gamedilong/anes-repository 15 | 16 | # Issues 17 | 18 | 这个插件是一个很初始版如果发现了任何的bug或者有任何建议, 请提交 issues to 到GitHub Repo https://github.com/gamedilong/anes-repository. 或者可以直接邮件到 1104238614@qq.com. -------------------------------------------------------------------------------- /resources/d2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/d0.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/runTest.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const { runTests } = require('vscode-test'); 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../'); 10 | 11 | // The path to the extension test script 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ] 16 | }, 17 | { 18 | "name": "Extension Tests", 19 | "type": "extensionHost", 20 | "request": "launch", 21 | "runtimeExecutable": "${execPath}", 22 | "args": [ 23 | "--extensionDevelopmentPath=${workspaceFolder}", 24 | "--extensionTestsPath=${workspaceFolder}/test/suite/index" 25 | ] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /view/vscode.call.js: -------------------------------------------------------------------------------- 1 | 2 | var vscode = acquireVsCodeApi(); 3 | var callbacks = {}; 4 | 5 | /** 6 | * 调用vscode原生api 7 | * @param data 可以是类似 {cmd: 'xxx', param1: 'xxx'},也可以直接是 cmd 字符串 8 | * @param cb 可选的回调函数 9 | */ 10 | function callVscode(data, cb) { 11 | if (typeof data === 'string') { 12 | data = { cmd: data }; 13 | } 14 | if (cb) { 15 | // 时间戳加上5位随机数 16 | const cbid = Date.now() + '' + Math.round(Math.random() * 100000); 17 | callbacks[cbid] = cb; 18 | data.cbid = cbid; 19 | } 20 | vscode.postMessage(data); 21 | } 22 | 23 | window.addEventListener('message', event => { 24 | const message = event.data; 25 | switch (message.cmd) { 26 | case 'vscodeCallback': 27 | (callbacks[message.cbid] || function () { })(message.data); 28 | delete callbacks[message.cbid]; 29 | break; 30 | default: break; 31 | } 32 | }); -------------------------------------------------------------------------------- /resources/rom.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/suite/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Mocha = require('mocha'); 3 | const glob = require('glob'); 4 | 5 | function run() { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | 40 | module.exports = { 41 | run 42 | }; 43 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | let color = [0x525252, 0xB40000, 0xA00000, 0xB1003D, 0x740069, 0x00005B, 0x00005F, 0x001840, 0x002F10, 0x084A08, 0x006700, 0x124200, 0x6D2800, 0x000000, 0x000000, 0x000000, 0xC4D5E7, 0xFF4000, 0xDC0E22, 0xFF476B, 0xD7009F, 0x680AD7, 0x0019BC, 0x0054B1, 0x006A5B, 0x008C03, 0x00AB00, 0x2C8800, 0xA47200, 0x000000, 0x000000, 0x000000, 0xF8F8F8, 0xFFAB3C, 0xFF7981, 0xFF5BC5, 0xFF48F2, 0xDF49FF, 0x476DFF, 0x00B4F7, 0x00E0FF, 0x00E375, 0x03F42B, 0x78B82E, 0xE5E218, 0x787878, 0x000000, 0x000000, 0xFFFFFF, 0xFFF2BE, 0xF8B8B8, 0xF8B8D8, 0xFFB6FF, 0xFFC3FF, 0xC7D1FF, 0x9ADAFF, 0x88EDF8, 0x83FFDD, 0xB8F8B8, 0xF5F8AC, 0xFFFFB0, 0xF8D8F8, 0x000000, 0x000000]; 2 | 3 | for(var i = 0 ; i < color.length ; i ++){ 4 | console.log(getRed(color[i]),getGreen(color[i]),getBlue(color[i])); 5 | } 6 | function getRed (rgb) { 7 | return (rgb >> 16) & 0xff; 8 | } 9 | 10 | function getGreen (rgb) { 11 | return (rgb >> 8) & 0xff; 12 | } 13 | 14 | function getBlue (rgb) { 15 | return rgb & 0xff; 16 | } -------------------------------------------------------------------------------- /resources/anes.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /view/controller.js: -------------------------------------------------------------------------------- 1 | function showControll(){ 2 | console.log('showControll') 3 | var modalbox = document.getElementById('modalbox'); 4 | console.log(modalbox) 5 | modalbox.style.display = 'block'; 6 | 7 | showKeyMap(); 8 | } 9 | 10 | 11 | function showKeyMap(){ 12 | document.getElementById('key1_left').innerText= NeskeyMap.BUTTON_UP; 13 | document.getElementById('key1_right'); 14 | document.getElementById('key1_up'); 15 | document.getElementById('key1_down'); 16 | document.getElementById('key1_a'); 17 | document.getElementById('key1_b'); 18 | document.getElementById('key1_down'); 19 | document.getElementById('key1_select'); 20 | } 21 | 22 | function closeControllSet(){ 23 | var modalbox = document.getElementById('modalbox'); 24 | modalbox.style.display = 'none'; 25 | } 26 | 27 | function changeGameColor(){ 28 | if(nes){ 29 | console.log('changeGameColor') 30 | nes.moyu = !nes.moyu 31 | nes.reloadROM(); 32 | } 33 | } 34 | 35 | function showImgMask(){ 36 | var imgMask = document.getElementById('imgMask'); 37 | imgMask.style.display = "block"; 38 | } 39 | 40 | 41 | function closeMask(){ 42 | var imgMask = document.getElementById('imgMask'); 43 | imgMask.style.display = "none"; 44 | } -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `extension.js` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `extension.js` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `extension.js`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 31 | * Press `F5` to run the tests in a new window with your extension loaded. 32 | * See the output of the test result in the debug console. 33 | * Make changes to `src/test/suite/extension.test.js` or create new test files inside the `test/suite` folder. 34 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 35 | * You can create folders inside the `test` folder to structure your tests any way you want. 36 | ## Go further 37 | 38 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 39 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 40 | -------------------------------------------------------------------------------- /romRemoteTree.js: -------------------------------------------------------------------------------- 1 | const vscode = require('vscode'); 2 | const FileUtil = require('./fileUtil'); 3 | const os = require('os'); 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | 7 | class RomRemoteTree { 8 | constructor(context){ 9 | this.context = context; 10 | this.userRoot = os.homedir(); 11 | this._onDidChangeTreeData = new vscode.EventEmitter(); 12 | this.onDidChangeTreeData = this._onDidChangeTreeData.event; 13 | if(!FileUtil.pathExists(path.join(this.userRoot, '.anes','remote'))) { 14 | //if not exists create default ahost floder 15 | try{ 16 | //FileUtil.createDefaultAHostFloder(this.userRoot,this.context); 17 | }catch(e){ 18 | //vscode.window.showInformationMessage('Ahost need Administrator permission!'); 19 | } 20 | } 21 | } 22 | refresh(){ 23 | this._onDidChangeTreeData.fire(); 24 | } 25 | getTreeItem(element){ 26 | return element; 27 | } 28 | getChildren(element) { 29 | let remoteRomConfig = FileUtil.getRemoteRomConfig(this.userRoot); 30 | let remoteMeta = fs.readFileSync(path.join(this.userRoot, '.anes', 'remote','meta.json')); 31 | remoteMeta = remoteMeta.toString(); 32 | remoteMeta = JSON.parse(remoteMeta); 33 | let remoteMetaMap = {}; 34 | remoteMeta.forEach((meta)=>{ 35 | remoteMetaMap[meta.name] = meta; 36 | }); 37 | if(remoteRomConfig && remoteRomConfig.length >0){ 38 | let remoteRomList = []; 39 | remoteRomConfig.forEach((config)=>{ 40 | let meta = remoteMetaMap[config.name] ? remoteMetaMap[config.name] : {} 41 | remoteRomList.push(new DataItem({ 42 | label:config.name, 43 | url:config.url, 44 | children: null, 45 | command: null, 46 | downloadStatus: meta.downloadStatus, 47 | fileName: config.fileName, 48 | nesName: config.nesName 49 | })); 50 | }); 51 | return remoteRomList; 52 | }else{ 53 | return []; 54 | } 55 | } 56 | } 57 | 58 | class DataItem extends vscode.TreeItem{ 59 | constructor({label, url, children, command, downloadStatus,fileName,nesName}) { 60 | super(label, vscode.TreeItemCollapsibleState.None); 61 | downloadStatus = downloadStatus ? downloadStatus : 0; // download 0 downloading 1 downloaded 2 62 | console.log(`downloadStatus:${downloadStatus}`); 63 | this.downloadStatus = downloadStatus; 64 | this.iconPath = path.join(__filename,'..','resources', `d0.svg`); 65 | this.children = children; 66 | this.command = command; 67 | this.url = url; 68 | this.fileName = fileName; 69 | this.nesName= nesName; 70 | } 71 | } 72 | 73 | module.exports = RomRemoteTree; -------------------------------------------------------------------------------- /fileUtil.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const META_FILE_NAME = 'meta.json'; 5 | 6 | const FileUtil = { 7 | pathExists: function(p) { 8 | try { 9 | fs.accessSync(p); 10 | } catch (err) { 11 | return false; 12 | } 13 | return true; 14 | }, 15 | createDefaultANesFloder:function(userRoot, context){ 16 | fs.mkdirSync(path.join(userRoot, '.anes')); 17 | fs.mkdirSync(path.join(userRoot, '.anes', 'local')); 18 | let defaultRomPath = FileUtil.getExtensionFileAbsolutePath(context, 'resources/demo.nes'); 19 | let basename= path.basename(defaultRomPath,'.nes'); 20 | let defaultRomDistPath = path.join(userRoot, '.anes','local',`${basename}.nes`,); 21 | 22 | this.copySync(defaultRomPath, defaultRomDistPath); 23 | this.writeMetaInfo(userRoot, 24 | [{ 25 | label: basename, 26 | path: defaultRomDistPath 27 | }] 28 | ) 29 | }, 30 | createDefaultRemoteFloder:function(){ 31 | //fs.mkdirSync(path.join(userRoot, '.anes')); 32 | fs.mkdirSync(path.join(userRoot, '.anes','remote')); 33 | 34 | }, 35 | writeMetaInfo:function(userRoot, metaInfo){ 36 | fs.writeFileSync(path.join(userRoot, '.anes', META_FILE_NAME),JSON.stringify(metaInfo)); 37 | }, 38 | addRomToResposity: function(userRoot, srcPath, gameName){ 39 | let fileName = path.basename(srcPath,'.nes'); 40 | let distPath = path.join(userRoot, '.anes', 'local',`${fileName}.nes`,); 41 | this.copySync(srcPath,distPath); 42 | let romConfigList = this.getRomConfigFileList(userRoot); 43 | romConfigList = romConfigList ? romConfigList : []; 44 | let exist = false; 45 | romConfigList.forEach(romConfig=>{ 46 | if(romConfig.label == fileName){ 47 | exist = true; 48 | } 49 | }) 50 | !exist && romConfigList.push({ 51 | label: gameName ? gameName : path.basename(srcPath), 52 | path: distPath 53 | }); 54 | this.writeMetaInfo(userRoot, romConfigList); 55 | }, 56 | getRomConfigFileList: function(userRoot){ 57 | let metaData = fs.readFileSync(path.join(userRoot, '.anes', META_FILE_NAME)); 58 | metaData = metaData.toString(); 59 | return JSON.parse(metaData); 60 | }, 61 | getRemoteRomConfig:function(userRoot){ 62 | let remoteList = fs.readFileSync(path.join(userRoot, '.anes','remote','anes-repository-master','list.json')); 63 | remoteList = remoteList.toString(); 64 | return JSON.parse(remoteList); 65 | }, 66 | getExtensionFileAbsolutePath:function(context, relativePath) { 67 | return path.join(context.extensionPath, relativePath); 68 | }, 69 | 70 | copySync:function(srcPath, distPath){ 71 | let data = fs.readFileSync(srcPath); 72 | fs.writeFileSync(distPath,data); 73 | } 74 | } 75 | 76 | module.exports = FileUtil; -------------------------------------------------------------------------------- /view/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 58 | 59 | 60 |操作说明: 上[W] 下[S] 左[A] 右[D] 开始 Enter 选择 Tap 攻击[J] 跳跃[k]
63 | 操作无反应时检查下是否游戏界面失去焦点,鼠标左键点击确认游戏界面获得输入焦点即可
64 |
微信
78 |
79 | 支付宝
82 |
83 |