Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
863 changes: 503 additions & 360 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 7 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "scratch-vm",
"version": "2.1.46",
"description": "Virtual Machine for Scratch 3.0",
"author": "Massachusetts Institute of Technology",
"name": "scbackend-vm",
"version": "11.45.26",
"description": "Scbackend定制版vm",
"author": "XQYWorld",
"license": "MPL-2.0",
"homepage": "https://github.com/scratchfoundation/scratch-vm#readme",
"repository": {
"type": "git",
"url": "https://github.com/scratchfoundation/scratch-vm.git"
"url": "https://github.com/scratchfoundation/scratch-vm.git",
"sha": "$(git log -n1 --pretty=format:%H)"
},
"main": "./src/index.js",
"browser": "./src/index.js",
Expand Down Expand Up @@ -81,8 +82,6 @@
"scratch-blocks": "0.1.0-prerelease.20230527085947",
"scratch-l10n": "3.16.20231222031921",
"scratch-render": "0.1.0-prerelease.20231220210403",
"scratch-render-fonts": "github:TurboWarp/scratch-render-fonts#master",
"scratch-storage": "2.3.1",
"script-loader": "0.7.2",
"stats.js": "0.17.0",
"tap": "16.2.0",
Expand All @@ -91,6 +90,5 @@
"webpack": "4.47.0",
"webpack-cli": "3.1.0",
"webpack-dev-server": "3.11.2"
},
"private": true
}
}
55 changes: 18 additions & 37 deletions src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,6 @@ class Runtime extends EventEmitter {
/**
* If set to true, features such as reading colors from the user's webcam will be disabled
* when the project has access to any external communication method to protect user privacy.
* Requires TurboWarp/scratch-render.
* Do not update this directly. Use Runtime.setEnforcePrivacy() instead.
*/
this.enforcePrivacy = true;
Expand Down Expand Up @@ -1930,18 +1929,20 @@ class Runtime extends EventEmitter {
* @param {!AudioEngine} audioEngine The audio engine to attach
*/
attachAudioEngine (audioEngine) {
this.audioEngine = audioEngine;
// 兼容性:无操作音频引擎
this.audioEngine = audioEngine || { createBank: () => ({}), getLoudness: () => 0 };
}

/**
* Attach the renderer
* @param {!RenderWebGL} renderer The renderer to attach
*/
attachRenderer (renderer) {
this.renderer = renderer;
this.renderer.setLayerGroupOrdering(StageLayering.LAYER_GROUPS);
this.renderer.offscreenTouching = !this.runtimeOptions.fencing;
this.updatePrivacy();
// 兼容性:无操作渲染器
this.renderer = renderer || { draw: () => {}, resize: () => {}, setLayerGroupOrdering: () => {}, setLayerOrdering: () => {}, setDrawableOrder: () => {}, updateDrawableProperties: () => {}, createDrawable: () => {}, destroyDrawable: () => {}, updateTexture: () => {}, isTouchingColor: () => false, pick: () => null };
if (this.renderer.setLayerGroupOrdering) this.renderer.setLayerGroupOrdering(StageLayering.LAYER_GROUPS);
if (this.renderer.hasOwnProperty('offscreenTouching')) this.renderer.offscreenTouching = !this.runtimeOptions.fencing;
this.updatePrivacy();
}

/**
Expand Down Expand Up @@ -2193,20 +2194,13 @@ class Runtime extends EventEmitter {
// No known hat with this opcode.
return;
}
const instance = this;
const newThreads = [];
// Look up metadata for the relevant hat.
const hatMeta = instance._hats[requestedHatOpcode];

for (const opts in optMatchFields) {
if (!Object.prototype.hasOwnProperty.call(optMatchFields, opts)) continue;
optMatchFields[opts] = optMatchFields[opts].toUpperCase();
}

// tw: By assuming that all new threads will not interfere with eachother, we can optimize the loops
// inside the allScriptsByOpcodeDo callback below.
const startingThreadListLength = this.threads.length;

// Consider all scripts, looking for hats with opcode `requestedHatOpcode`.
this.allScriptsByOpcodeDo(requestedHatOpcode, (script, target) => {
const {
Expand All @@ -2225,30 +2219,6 @@ class Runtime extends EventEmitter {
return;
}
}

if (hatMeta.restartExistingThreads) {
// If `restartExistingThreads` is true, we should stop
// any existing threads starting with the top block.
const existingThread = this.threadMap.get(Thread.getIdFromTargetAndBlock(target, topBlockId));
if (existingThread) {
newThreads.push(this._restartThread(existingThread));
return;
}
} else {
// If `restartExistingThreads` is false, we should
// give up if any threads with the top block are running.
for (let j = 0; j < startingThreadListLength; j++) {
if (this.threads[j].target === target &&
this.threads[j].topBlock === topBlockId &&
// stack click threads and hat threads can coexist
!this.threads[j].stackClick &&
this.threads[j].status !== Thread.STATUS_DONE) {
// Some thread is already running.
return;
}
}
}
// Start the thread with this top block.
newThreads.push(this._pushThread(topBlockId, target));
}, optTarget);
// For compatibility with Scratch 2, edge triggered hats need to be processed before
Expand All @@ -2270,6 +2240,17 @@ class Runtime extends EventEmitter {
return newThreads;
}

startHatsWithParams (requestedHatOpcode, optParams, optMatchFields, optTarget) {
return this.startHats(requestedHatOpcode, optMatchFields, optTarget).forEach(thread => {
if (optParams) {
thread.initParams();
for (const i of Object.keys(optParams)) {
thread.pushParam(i, optParams[i]);
}
}
});
}


/**
* Dispose all targets. Return to clean state.
Expand Down
3 changes: 1 addition & 2 deletions src/engine/sequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ class Sequencer {
// 3. Either turbo mode, or no redraw has been requested by a primitive.
while (this.runtime.threads.length > 0 &&
numActiveThreads > 0 &&
this.timer.timeElapsed() < WORK_TIME &&
(this.runtime.turboMode || !this.runtime.redrawRequested)) {
this.timer.timeElapsed() < WORK_TIME) {
if (this.runtime.profiler !== null) {
if (stepThreadsInnerProfilerId === -1) {
stepThreadsInnerProfilerId = this.runtime.profiler.idByName(stepThreadsInnerProfilerFrame);
Expand Down
16 changes: 1 addition & 15 deletions src/extension-support/extension-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,8 @@ const SecurityManager = require('./tw-security-manager');
// TODO: change extension spec so that library info, including extension ID, can be collected through static methods

const defaultBuiltinExtensions = {
// This is an example that isn't loaded with the other core blocks,
// but serves as a reference for loading core blocks as extensions.
coreExample: () => require('../blocks/scratch3_core_example'),
// These are the non-core built-in extensions.
pen: () => require('../extensions/scratch3_pen'),
wedo2: () => require('../extensions/scratch3_wedo2'),
music: () => require('../extensions/scratch3_music'),
microbit: () => require('../extensions/scratch3_microbit'),
text2speech: () => require('../extensions/scratch3_text2speech'),
translate: () => require('../extensions/scratch3_translate'),
videoSensing: () => require('../extensions/scratch3_video_sensing'),
ev3: () => require('../extensions/scratch3_ev3'),
makeymakey: () => require('../extensions/scratch3_makeymakey'),
boost: () => require('../extensions/scratch3_boost'),
gdxfor: () => require('../extensions/scratch3_gdx_for'),
// tw: core extension
scbackendbasic: () => require('../extensions/scbackend_basic'),
tw: () => require('../extensions/tw')
};

Expand Down
110 changes: 110 additions & 0 deletions src/extensions/scbackend_basic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
class ScbackendBasicExtension {
constructor(runtime) {
this.runtime = runtime;
}

getInfo() {
const basicblocks = [
{
opcode: 'newconnect',
blockType: 'event',
text: '当新的连接收到',
isEdgeActivated: false
},
{
opcode: 'lastconnect',
blockType: 'reporter',
text: '最后一次连接的id',
},
{
opcode: 'message',
blockType: 'event',
text: '当收到消息',
isEdgeActivated: false
},
{
opcode: 'getdata',
blockType: 'reporter',
text: '收到的数据'
},
{
opcode: 'getsrc',
blockType: 'reporter',
text: '收到的消息来源id'
},
{
opcode: 'sendmessage',
blockType: 'command',
text: '向 [connectid] 发送消息 [message]',
arguments: {
connectid: {
type: 'string',
defaultValue: 'connectid',
},
message: {
type: 'string',
defaultValue: 'message',
}
}
},
{
opcode: 'log',
blockType: 'command',
text: '打印 [message] 到控制台',
arguments: {
message: {
type: 'string',
defaultValue: 'message',
}
}
}
];
return {
id: 'scbackendbasic',
name: 'scbackend基础接口',
blocks: basicblocks
};
}

lastconnect(args, util) {
if (!this.runtime || !this.runtime.scbackend) {
return '';
}
return util.thread.getParam('sessionid') || '';
}

getsrc(args, util) {
if (!this.runtime || !this.runtime.scbackend) {
return '';
}
return util.thread.getParam('srcid') || '';
}

sendmessage(args) {
const { connectid, message } = args;
if (!this.runtime || !this.runtime.scbackend) {
return;
}
this.runtime.scbackend.send('message', {dst: connectid, body: message});
}

getdata(args, util) {
if (!this.runtime || !this.runtime.scbackend) {
return '';
}
return util.thread.getParam('data') || '';
}
log(args) {
const { message } = args;
if (!this.runtime || !this.runtime.scbackend) {
return;
}
this.runtime.scbackend.send('log', {body: message});
}
}

if (typeof Scratch !== 'undefined') {
Scratch.extensions.register(new ScbackendBasicExtension());
} else {
module.exports = ScbackendBasicExtension;
}
1 change: 0 additions & 1 deletion src/import/load-costume.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,6 @@ const fetchBitmapCanvas_ = function (costume, runtime, rotationCenter) {
}
}

// This informs TurboWarp/scratch-render that this canvas won't be reused by the canvas pool,
// which helps it optimize memory use.
imageOrCanvas.reusable = false;

Expand Down
1 change: 0 additions & 1 deletion src/io/video.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ class Video {
this._drawable = renderer.createDrawable(StageLayering.VIDEO_LAYER);
renderer.updateDrawableSkinId(this._drawable, this._skinId);
// TW: Video probably contains the user's face. This is private information.
// This API won't exist if we're using a vanilla scratch-render
if (renderer.markSkinAsPrivate) {
renderer.markSkinAsPrivate(this._skinId);
}
Expand Down
8 changes: 4 additions & 4 deletions src/playground/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ const ScratchStorage = require('scratch-storage');
const VirtualMachine = require('..');
const Runtime = require('../engine/runtime');

const ScratchRender = require('scratch-render');
const AudioEngine = require('scratch-audio');
const ScratchSVGRenderer = require('@turbowarp/scratch-svg-renderer');

const Scratch = window.Scratch = window.Scratch || {};
Expand Down Expand Up @@ -679,10 +677,12 @@ const runBenchmark = function () {

// Instantiate the renderer and connect it to the VM.
const canvas = document.getElementById('scratch-stage');
const renderer = new ScratchRender(canvas);
// 兼容性:无操作渲染器
const renderer = { draw: () => {}, resize: () => {}, setLayerGroupOrdering: () => {}, setLayerOrdering: () => {}, setDrawableOrder: () => {}, updateDrawableProperties: () => {}, createDrawable: () => {}, destroyDrawable: () => {}, updateTexture: () => {}, isTouchingColor: () => false, pick: () => null };
Scratch.renderer = renderer;
vm.attachRenderer(renderer);
const audioEngine = new AudioEngine();
// 兼容性:无操作音频引擎
const audioEngine = { createBank: () => ({}), getLoudness: () => 0 };
vm.attachAudioEngine(audioEngine);
vm.attachV2BitmapAdapter(new ScratchSVGRenderer.BitmapAdapter());

Expand Down
1 change: 0 additions & 1 deletion src/playground/video-sensing.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<!-- Storage module -->
<script src="./scratch-storage.js"></script>
<!-- Stage rendering -->
<script src="./scratch-render.js"></script>
<!-- Extension -->
<script src="./video-sensing-extension-debug.js"></script>
<!-- Motion -->
Expand Down
11 changes: 8 additions & 3 deletions src/util/log.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
const nanolog = require('@turbowarp/nanolog');
nanolog.enable();
// const nanolog = require('@turbowarp/nanolog');
// nanolog.enable();

module.exports = nanolog('vm');
// module.exports = nanolog('vm');
module.exports = {
log: _ => {},
warn: _ => {},
error: _ => {}
};
6 changes: 4 additions & 2 deletions src/virtual-machine.js
Original file line number Diff line number Diff line change
Expand Up @@ -1416,15 +1416,17 @@ class VirtualMachine extends EventEmitter {
* @param {!AudioEngine} audioEngine The audio engine to attach
*/
attachAudioEngine (audioEngine) {
this.runtime.attachAudioEngine(audioEngine);
// 兼容性:无操作音频引擎
this.runtime.attachAudioEngine(audioEngine || { createBank: () => ({}), getLoudness: () => 0 });
}

/**
* Set the renderer for the VM/runtime
* @param {!RenderWebGL} renderer The renderer to attach
*/
attachRenderer (renderer) {
this.runtime.attachRenderer(renderer);
// 兼容性:无操作渲染器
this.runtime.attachRenderer(renderer || { draw: () => {}, resize: () => {}, setLayerGroupOrdering: () => {}, setLayerOrdering: () => {}, setDrawableOrder: () => {}, updateDrawableProperties: () => {}, createDrawable: () => {}, destroyDrawable: () => {}, updateTexture: () => {}, isTouchingColor: () => false, pick: () => null });
}

/**
Expand Down
1 change: 0 additions & 1 deletion test/unit/extension_video_sensing.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ const isNearAngle = (actual, expect, optMargin = 10) => (
(wrapClamp(actual - expect, 0, 359) > 360 - optMargin)
);

// A fake scratch-render drawable that will be used by VideoMotion to restrain
// the area considered for motion detection in VideoMotion.getLocalMotion
const fakeDrawable = {
updateCPURenderAttributes () {}, // no-op, since isTouching always returns true
Expand Down
Loading