pxt-microbit 5.1.3 → 5.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -773,7 +773,8 @@ declare namespace pxsim {
773
773
  }
774
774
  }
775
775
  declare namespace pxsim.multiplayer {
776
- function postImage(im: pxsim.RefImage, goal: string): void;
776
+ function postImage(im: pxsim.RefImage): void;
777
+ function postIcon(iconType: IconType, slot: number, im: pxsim.RefImage): void;
777
778
  function getCurrentImage(): pxsim.RefImage;
778
779
  function setOrigin(origin: "client" | "server" | undefined): void;
779
780
  function getOrigin(): string;
@@ -793,14 +794,35 @@ declare namespace pxsim {
793
794
  }
794
795
  interface MultiplayerImageMessage extends SimulatorMultiplayerMessage {
795
796
  content: "Image";
796
- goal: string;
797
- image: RefImage;
797
+ image: RefBuffer;
798
+ palette: Uint8Array;
799
+ }
800
+ enum IconType {
801
+ Player = 0,
802
+ Reaction = 1
803
+ }
804
+ interface MultiplayerIconMessage extends SimulatorMultiplayerMessage {
805
+ content: "Icon";
806
+ icon: RefBuffer;
807
+ slot: number;
808
+ iconType: IconType;
809
+ palette: Uint8Array;
798
810
  }
799
811
  interface MultiplayerButtonEvent extends SimulatorMultiplayerMessage {
800
812
  content: "Button";
801
813
  button: number;
802
814
  state: "Pressed" | "Released" | "Held";
803
815
  }
816
+ interface MultiplayerAudioEvent extends SimulatorMultiplayerMessage {
817
+ content: "Audio";
818
+ instruction: "playinstructions" | "muteallchannels";
819
+ soundbuf?: Uint8Array;
820
+ }
821
+ interface MultiplayerConnectionEvent extends SimulatorMultiplayerMessage {
822
+ content: "Connection";
823
+ slot: number;
824
+ connected: boolean;
825
+ }
804
826
  class MultiplayerState {
805
827
  lastMessageId: number;
806
828
  origin: string;
@@ -809,6 +831,7 @@ declare namespace pxsim {
809
831
  send(msg: SimulatorMultiplayerMessage): void;
810
832
  init(origin: string): void;
811
833
  setButton(key: number, isPressed: boolean): void;
834
+ registerConnectionState(player: number, connected: boolean): void;
812
835
  protected messageHandler(msg: SimulatorMessage): void;
813
836
  }
814
837
  }
@@ -924,6 +947,20 @@ declare namespace pxsim.music {
924
947
  function queuePlayInstructions(when: number, b: RefBuffer): void;
925
948
  function stopPlaying(): void;
926
949
  function forceOutput(mode: number): void;
950
+ const SEQUENCER_STOP_MESSAGE = 3243;
951
+ const SEQUENCER_TICK_MESSAGE = 3244;
952
+ const SEQUENCER_STATE_CHANGE_MESSAGE = 3245;
953
+ const SEQUENCER_LOOPED_MESSAGE = 3246;
954
+ function _createSequencer(): Promise<number>;
955
+ function _sequencerState(id: number): string;
956
+ function _sequencerCurrentTick(id: number): number;
957
+ function _sequencerPlaySong(id: number, song: RefBuffer, loop: boolean): void;
958
+ function _sequencerStop(id: number): void;
959
+ function _sequencerSetVolume(id: number, volume: number): void;
960
+ function _sequencerSetVolumeForAll(volume: number): void;
961
+ function _sequencerSetTrackVolume(id: number, trackIndex: number, volume: number): void;
962
+ function _sequencerSetDrumTrackVolume(id: number, trackIndex: number, drumIndex: number, volume: number): void;
963
+ function _sequencerDispose(id: number): void;
927
964
  }
928
965
  declare namespace pxsim.mouse {
929
966
  function setButton(button: number, down: boolean): void;
@@ -1131,6 +1168,8 @@ declare namespace pxsim {
1131
1168
  onChange: () => void;
1132
1169
  constructor(paletteSrc: string[], w?: number, h?: number);
1133
1170
  setScreenBrightness(b: number): void;
1171
+ paletteToUint8Array(): Uint8Array;
1172
+ setPaletteFromHtmlColors(src: string[]): void;
1134
1173
  setPalette(buf: RefBuffer): void;
1135
1174
  bpp(): 1 | 4;
1136
1175
  didChange(): boolean;
@@ -1166,8 +1205,8 @@ declare namespace pxsim.visuals {
1166
1205
  }
1167
1206
  }
1168
1207
  declare namespace pxsim.settings {
1169
- function _set(key: string, buf: RefBuffer): -1 | 0;
1170
- function _remove(key: string): -1 | 0;
1208
+ function _set(key: string, buf: RefBuffer): 0 | -1;
1209
+ function _remove(key: string): 0 | -1;
1171
1210
  function _exists(key: string): boolean;
1172
1211
  function _get(key: string): RefBuffer;
1173
1212
  function _userClean(): void;
@@ -2467,8 +2467,8 @@ var pxsim;
2467
2467
  // System keymap
2468
2468
  this.setSystemKeys(80, // P - Screenshot
2469
2469
  82, // R - Gif
2470
- 0, // Menu - not mapped
2471
- 0 // Reset - not mapped
2470
+ 192, // Menu - '`' (backtick) button
2471
+ 8 // Reset - Backspace button
2472
2472
  );
2473
2473
  // Player 1 alternate mapping. This is cleared when the game sets any player keys explicitly
2474
2474
  this.altmap[38] = Key.Up; // UpArrow
@@ -2527,7 +2527,7 @@ var pxsim;
2527
2527
  }
2528
2528
  clearMap(name) {
2529
2529
  const keyCodes = this.mappings[name];
2530
- keyCodes === null || keyCodes === void 0 ? void 0 : keyCodes.forEach(keyCode => delete this.keymap[keyCode]);
2530
+ keyCodes && keyCodes.forEach(keyCode => delete this.keymap[keyCode]);
2531
2531
  delete this.mappings[name];
2532
2532
  }
2533
2533
  }
@@ -2537,15 +2537,41 @@ var pxsim;
2537
2537
  (function (pxsim) {
2538
2538
  var multiplayer;
2539
2539
  (function (multiplayer) {
2540
- function postImage(im, goal) {
2540
+ const throttledImgPost = pxsim.U.throttle((msg) => {
2541
+ pxsim.getMultiplayerState().send(msg);
2542
+ }, 50, true);
2543
+ function postImage(im) {
2544
+ if (pxsim.getMultiplayerState().origin !== "server")
2545
+ return;
2541
2546
  const asBuf = pxsim.image.toBuffer(im);
2542
- pxsim.getMultiplayerState().send({
2547
+ const sb = pxsim.board();
2548
+ const screenState = sb && sb.screenState;
2549
+ throttledImgPost({
2543
2550
  content: "Image",
2544
2551
  image: asBuf,
2545
- goal
2552
+ palette: screenState && screenState.paletteToUint8Array(),
2546
2553
  });
2547
2554
  }
2548
2555
  multiplayer.postImage = postImage;
2556
+ function postIcon(iconType, slot, im) {
2557
+ if (im && (im._width * im._height > 64 * 64)) {
2558
+ // setting 64x64 as max size for icon for now
2559
+ return;
2560
+ }
2561
+ // treat empty icon as undefined
2562
+ const asBuf = (im && im.data.some(pixel => pixel != 0))
2563
+ ? pxsim.image.toBuffer(im) : undefined;
2564
+ const sb = pxsim.board();
2565
+ const screenState = sb && sb.screenState;
2566
+ pxsim.getMultiplayerState().send({
2567
+ content: "Icon",
2568
+ slot: slot,
2569
+ icon: asBuf,
2570
+ iconType: iconType,
2571
+ palette: screenState.paletteToUint8Array(),
2572
+ });
2573
+ }
2574
+ multiplayer.postIcon = postIcon;
2549
2575
  function getCurrentImage() {
2550
2576
  return pxsim.getMultiplayerState().backgroundImage;
2551
2577
  }
@@ -2565,6 +2591,13 @@ var pxsim;
2565
2591
  return pxsim.board().multiplayerState;
2566
2592
  }
2567
2593
  pxsim.getMultiplayerState = getMultiplayerState;
2594
+ let IconType;
2595
+ (function (IconType) {
2596
+ IconType[IconType["Player"] = 0] = "Player";
2597
+ IconType[IconType["Reaction"] = 1] = "Reaction";
2598
+ })(IconType = pxsim.IconType || (pxsim.IconType = {}));
2599
+ const MULTIPLAYER_PLAYER_JOINED_ID = 3241;
2600
+ const MULTIPLAYER_PLAYER_LEFT_ID = 3242;
2568
2601
  class MultiplayerState {
2569
2602
  constructor() {
2570
2603
  this.lastMessageId = 0;
@@ -2575,14 +2608,18 @@ var pxsim;
2575
2608
  init(origin) {
2576
2609
  this.origin = origin;
2577
2610
  pxsim.runtime.board.addMessageListener(msg => this.messageHandler(msg));
2578
- setInterval(() => {
2579
- if (this.origin === "server") {
2580
- const b = pxsim.board();
2581
- const screenState = b && b.screenState;
2582
- const lastImage = screenState && screenState.lastImage;
2583
- lastImage && pxsim.multiplayer.postImage(lastImage, "broadcast-screen");
2584
- }
2585
- }, 50);
2611
+ if (this.origin === "server") {
2612
+ pxsim.AudioContextManager.soundEventCallback = (ev, data) => {
2613
+ this.send({
2614
+ content: "Audio",
2615
+ instruction: ev,
2616
+ soundbuf: data,
2617
+ });
2618
+ };
2619
+ }
2620
+ else {
2621
+ pxsim.AudioContextManager.soundEventCallback = undefined;
2622
+ }
2586
2623
  }
2587
2624
  setButton(key, isPressed) {
2588
2625
  if (this.origin === "client") {
@@ -2593,6 +2630,11 @@ var pxsim;
2593
2630
  });
2594
2631
  }
2595
2632
  }
2633
+ registerConnectionState(player, connected) {
2634
+ const evId = connected ? MULTIPLAYER_PLAYER_JOINED_ID : MULTIPLAYER_PLAYER_LEFT_ID;
2635
+ const b = pxsim.board();
2636
+ b.bus.queue(evId, player);
2637
+ }
2596
2638
  messageHandler(msg) {
2597
2639
  if (!isMultiplayerMessage(msg)) {
2598
2640
  return;
@@ -2604,14 +2646,31 @@ var pxsim;
2604
2646
  msg.image.data = new Uint8Array(msg.image.data);
2605
2647
  }
2606
2648
  this.backgroundImage = pxsim.image.ofBuffer(msg.image);
2649
+ if (msg.palette && msg.palette.length === 48) {
2650
+ const palBuffer = new pxsim.RefBuffer(msg.palette);
2651
+ pxsim.pxtcore.setPalette(palBuffer);
2652
+ }
2607
2653
  }
2608
2654
  }
2609
2655
  else if (isButtonMessage(msg)) {
2610
2656
  if (this.origin === "server") {
2611
- pxsim.board().setButton(msg.button + (7 * (msg.clientNumber || 1)), // + 7 to make it player 2 controls,
2657
+ pxsim.board().handleKeyEvent(msg.button + (7 * (msg.clientNumber || 1)), // + 7 to make it player 2 controls,
2612
2658
  msg.state === "Pressed" || msg.state === "Held");
2613
2659
  }
2614
2660
  }
2661
+ else if (isAudioMessage(msg)) {
2662
+ if (this.origin === "client") {
2663
+ if (msg.instruction === "playinstructions") {
2664
+ pxsim.AudioContextManager.playInstructionsAsync(msg.soundbuf);
2665
+ }
2666
+ else if (msg.instruction === "muteallchannels") {
2667
+ pxsim.AudioContextManager.muteAllChannels();
2668
+ }
2669
+ }
2670
+ }
2671
+ else if (isConnectionMessage(msg)) {
2672
+ this.registerConnectionState(msg.slot, msg.connected);
2673
+ }
2615
2674
  }
2616
2675
  }
2617
2676
  pxsim.MultiplayerState = MultiplayerState;
@@ -2624,6 +2683,12 @@ var pxsim;
2624
2683
  function isButtonMessage(msg) {
2625
2684
  return msg && msg.content === "Button";
2626
2685
  }
2686
+ function isAudioMessage(msg) {
2687
+ return msg && msg.content === "Audio";
2688
+ }
2689
+ function isConnectionMessage(msg) {
2690
+ return msg && msg.content === "Connection";
2691
+ }
2627
2692
  })(pxsim || (pxsim = {}));
2628
2693
  var pxsim;
2629
2694
  (function (pxsim) {
@@ -3126,7 +3191,7 @@ var pxsim;
3126
3191
  var music;
3127
3192
  (function (music) {
3128
3193
  function playInstructions(b) {
3129
- return pxsim.AudioContextManager.playInstructionsAsync(b);
3194
+ return pxsim.AudioContextManager.playInstructionsAsync(b.data);
3130
3195
  }
3131
3196
  music.playInstructions = playInstructions;
3132
3197
  function queuePlayInstructions(when, b) {
@@ -3135,10 +3200,108 @@ var pxsim;
3135
3200
  music.queuePlayInstructions = queuePlayInstructions;
3136
3201
  function stopPlaying() {
3137
3202
  pxsim.AudioContextManager.muteAllChannels();
3203
+ if (sequencers) {
3204
+ for (const seq of sequencers) {
3205
+ seq.sequencer.stop();
3206
+ seq.sequencer.dispose();
3207
+ }
3208
+ }
3138
3209
  }
3139
3210
  music.stopPlaying = stopPlaying;
3140
3211
  function forceOutput(mode) { }
3141
3212
  music.forceOutput = forceOutput;
3213
+ music.SEQUENCER_STOP_MESSAGE = 3243;
3214
+ music.SEQUENCER_TICK_MESSAGE = 3244;
3215
+ music.SEQUENCER_STATE_CHANGE_MESSAGE = 3245;
3216
+ music.SEQUENCER_LOOPED_MESSAGE = 3246;
3217
+ let sequencers;
3218
+ let nextSequencerId = 0;
3219
+ async function _createSequencer() {
3220
+ if (!sequencers) {
3221
+ pxsim.AudioContextManager.onStopAll(() => {
3222
+ for (const seq of sequencers) {
3223
+ seq.sequencer.stop();
3224
+ seq.sequencer.dispose();
3225
+ }
3226
+ sequencers = [];
3227
+ });
3228
+ sequencers = [];
3229
+ }
3230
+ const res = {
3231
+ id: nextSequencerId++,
3232
+ sequencer: new music.Sequencer()
3233
+ };
3234
+ sequencers.push(res);
3235
+ await res.sequencer.initAsync();
3236
+ res.sequencer.addEventListener("stop", () => {
3237
+ pxsim.board().bus.queue(music.SEQUENCER_STOP_MESSAGE, this.id);
3238
+ });
3239
+ res.sequencer.addEventListener("state-change", () => {
3240
+ pxsim.board().bus.queue(music.SEQUENCER_STATE_CHANGE_MESSAGE, this.id);
3241
+ });
3242
+ res.sequencer.addEventListener("looped", () => {
3243
+ pxsim.board().bus.queue(music.SEQUENCER_LOOPED_MESSAGE, this.id);
3244
+ });
3245
+ res.sequencer.addEventListener("tick", () => {
3246
+ pxsim.board().bus.queue(music.SEQUENCER_TICK_MESSAGE, this.id);
3247
+ });
3248
+ return res.id;
3249
+ }
3250
+ music._createSequencer = _createSequencer;
3251
+ function _sequencerState(id) {
3252
+ var _a;
3253
+ return (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.state();
3254
+ }
3255
+ music._sequencerState = _sequencerState;
3256
+ function _sequencerCurrentTick(id) {
3257
+ var _a;
3258
+ return (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.currentTick();
3259
+ }
3260
+ music._sequencerCurrentTick = _sequencerCurrentTick;
3261
+ function _sequencerPlaySong(id, song, loop) {
3262
+ var _a;
3263
+ const decoded = music.decodeSong(song.data);
3264
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.start(decoded, loop);
3265
+ }
3266
+ music._sequencerPlaySong = _sequencerPlaySong;
3267
+ function _sequencerStop(id) {
3268
+ var _a;
3269
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.stop();
3270
+ }
3271
+ music._sequencerStop = _sequencerStop;
3272
+ function _sequencerSetVolume(id, volume) {
3273
+ var _a;
3274
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.setVolume(volume);
3275
+ }
3276
+ music._sequencerSetVolume = _sequencerSetVolume;
3277
+ function _sequencerSetVolumeForAll(volume) {
3278
+ for (const seq of sequencers) {
3279
+ seq.sequencer.setVolume(volume);
3280
+ }
3281
+ }
3282
+ music._sequencerSetVolumeForAll = _sequencerSetVolumeForAll;
3283
+ function _sequencerSetTrackVolume(id, trackIndex, volume) {
3284
+ var _a;
3285
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.setTrackVolume(trackIndex, volume);
3286
+ }
3287
+ music._sequencerSetTrackVolume = _sequencerSetTrackVolume;
3288
+ function _sequencerSetDrumTrackVolume(id, trackIndex, drumIndex, volume) {
3289
+ var _a;
3290
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.setDrumTrackVolume(trackIndex, drumIndex, volume);
3291
+ }
3292
+ music._sequencerSetDrumTrackVolume = _sequencerSetDrumTrackVolume;
3293
+ function _sequencerDispose(id) {
3294
+ var _a;
3295
+ (_a = lookupSequencer(id)) === null || _a === void 0 ? void 0 : _a.dispose();
3296
+ sequencers = sequencers.filter(s => s.id !== id);
3297
+ }
3298
+ music._sequencerDispose = _sequencerDispose;
3299
+ function lookupSequencer(id) {
3300
+ for (const seq of sequencers)
3301
+ if (seq.id === id)
3302
+ return seq.sequencer;
3303
+ return undefined;
3304
+ }
3142
3305
  })(music = pxsim.music || (pxsim.music = {}));
3143
3306
  })(pxsim || (pxsim = {}));
3144
3307
  var pxsim;
@@ -3706,7 +3869,7 @@ var pxsim;
3706
3869
  let hh = 0;
3707
3870
  while (len--) {
3708
3871
  if (hh++ >= img._height) {
3709
- hh = 0;
3872
+ hh = 1;
3710
3873
  sp = ++x;
3711
3874
  }
3712
3875
  dst.data[dp++] = img.data[sp];
@@ -3724,7 +3887,7 @@ var pxsim;
3724
3887
  let hh = 0;
3725
3888
  while (len--) {
3726
3889
  if (hh++ >= img._height) {
3727
- hh = 0;
3890
+ hh = 1;
3728
3891
  dp = ++x;
3729
3892
  }
3730
3893
  img.data[dp] = src.data[sp++];
@@ -4260,6 +4423,9 @@ var pxsim;
4260
4423
  }
4261
4424
  image.isValidImage = isValidImage;
4262
4425
  function create(w, h) {
4426
+ // truncate decimal sizes
4427
+ w |= 0;
4428
+ h |= 0;
4263
4429
  return new pxsim.RefImage(w, h, pxsim.getScreenState().bpp());
4264
4430
  }
4265
4431
  image.create = create;
@@ -4419,7 +4585,6 @@ var pxsim;
4419
4585
  (function (pxsim) {
4420
4586
  function htmlColorToUint32(hexColor) {
4421
4587
  const ca = new Uint8ClampedArray(4);
4422
- const ui = new Uint32Array(ca.buffer);
4423
4588
  const v = parseInt(hexColor.replace(/#/, ""), 16);
4424
4589
  ca[0] = (v >> 16) & 0xff;
4425
4590
  ca[1] = (v >> 8) & 0xff;
@@ -4428,6 +4593,12 @@ var pxsim;
4428
4593
  // convert to uint32 using target endian
4429
4594
  return new Uint32Array(ca.buffer)[0];
4430
4595
  }
4596
+ function UInt32ToRGB(col) {
4597
+ const ui = new Uint32Array(1);
4598
+ ui[0] = col;
4599
+ const ca = new Uint8ClampedArray(ui.buffer);
4600
+ return [ca[0], ca[1], ca[2]];
4601
+ }
4431
4602
  class ScreenState {
4432
4603
  constructor(paletteSrc, w = 0, h = 0) {
4433
4604
  this.width = 0;
@@ -4439,9 +4610,7 @@ var pxsim;
4439
4610
  if (!paletteSrc)
4440
4611
  paletteSrc = ["#000000", "#ffffff"];
4441
4612
  this.palette = new Uint32Array(paletteSrc.length);
4442
- for (let i = 0; i < this.palette.length; ++i) {
4443
- this.palette[i] = htmlColorToUint32(paletteSrc[i]);
4444
- }
4613
+ this.setPaletteFromHtmlColors(paletteSrc);
4445
4614
  if (w) {
4446
4615
  this.width = w;
4447
4616
  this.height = h;
@@ -4452,6 +4621,22 @@ var pxsim;
4452
4621
  setScreenBrightness(b) {
4453
4622
  this.brightness = b | 0;
4454
4623
  }
4624
+ paletteToUint8Array() {
4625
+ const out = new Uint8Array(this.palette.length * 3);
4626
+ for (let i = 0; i < this.palette.length; ++i) {
4627
+ const [r, g, b] = UInt32ToRGB(this.palette[i]);
4628
+ const s = 3 * i;
4629
+ out[s] = r;
4630
+ out[s + 1] = g;
4631
+ out[s + 2] = b;
4632
+ }
4633
+ return out;
4634
+ }
4635
+ setPaletteFromHtmlColors(src) {
4636
+ for (let i = 0; i < this.palette.length; ++i) {
4637
+ this.palette[i] = htmlColorToUint32(src[i]);
4638
+ }
4639
+ }
4455
4640
  setPalette(buf) {
4456
4641
  const ca = new Uint8ClampedArray(4);
4457
4642
  const rd = new Uint32Array(ca.buffer);
package/built/editor.js CHANGED
@@ -3373,7 +3373,18 @@ class DAPWrapper {
3373
3373
  isConnecting() {
3374
3374
  return this.io.isConnecting() || (this.io.isConnected() && !this.initialized);
3375
3375
  }
3376
+ async getBaudRate() {
3377
+ const readSerialSettings = new Uint8Array([0x81]); // get serial settings
3378
+ const serialSettings = await this.dapCmd(readSerialSettings);
3379
+ const baud = (serialSettings[4] << 24) + (serialSettings[3] << 16) + (serialSettings[2] << 8) + serialSettings[1];
3380
+ return baud;
3381
+ }
3376
3382
  async setBaudRate() {
3383
+ const currentBaudRate = await this.getBaudRate();
3384
+ if (currentBaudRate === 115200) {
3385
+ log(`baud rate already set to 115200`);
3386
+ return;
3387
+ }
3377
3388
  log(`set baud rate to 115200`);
3378
3389
  const baud = new Uint8Array(5);
3379
3390
  baud[0] = 0x82; // set baud