Skip to content

Instantly share code, notes, and snippets.

@szdytom
Last active October 16, 2023 08:28
Show Gist options
  • Save szdytom/75201748888c589b746c60fbc25a7524 to your computer and use it in GitHub Desktop.
Save szdytom/75201748888c589b746c60fbc25a7524 to your computer and use it in GitHub Desktop.
[Minecraft] Play music score inside books!
__config() -> {
'scope' -> 'global',
};
global_playList = {};
global_playListCounter = 1;
readBook(itemTuple) -> (
itemNbt = itemTuple:2;
content = '';
c_for(i = 0, true, i += 1, (
contentPageI = itemNbt:('pages[' + str(i) + ']');
if (contentPageI == null, (
return(content);
));
content += contentPageI;
));
content
);
scoreFormat(sourceMusic) -> (
if(slice(sourceMusic, 0, 14) == 'NOTEBOX_SONG_1', 1, 0)
);
extractTitle(sourceMusicHeader) -> (
mL = decode_json('{' + slice(sourceMusicHeader, 15) + '}');
mL:'Title'
);
calcPitch(level) -> (
2 ^ ((level - 12) / 12)
);
parseTrack(trackSource) -> (
trackSource = split('\\s+', replace_first(trackSource, '\\s+\\d+:', ''));
res = [];
cSpeed = 1;
cVolumn = 1;
cType = 'harp';
cTick = 0;
for(trackSource, (
if(length(_) == 0, continue());
if(slice(_, 0, 1) == '-', (
cTick += cSpeed;
continue();
));
if(slice(_, 0, 1) == '[', (
attrubuteParts = split(',', slice(_, 1, length(_) - 1));
cVolumn = number(attrubuteParts:0);
cType = attrubuteParts:1;
cSpeed = number(attrubuteParts:2);
continue();
));
pitchParts = split('\\+', _);
for(pitchParts, (
put(res, null, [cTick, cVolumn, cType, calcPitch(number(_))]);
));
cTick += cSpeed;
));
return(res);
);
parseScoreBook(itemTuple) -> (
try((
if(itemTuple:0 != 'writable_book' && itemTuple:0 != 'written_book', return(null));
content = readBook(itemTuple);
if(scoreFormat(content) == 0, return(null));
content = split('Track', content);
scoreTitle = extractTitle(content:0);
track_n = length(content) - 1;
musicNotes = [];
c_for(i = 1, i <= track_n, i += 1, (
put(musicNotes, null, parseTrack(content:i), 'extend');
));
musicNotes = sort_key(musicNotes, _:0);
global_playListCounter += 1;
return({'title' -> scoreTitle, 'notes' -> musicNotes, 'length' -> length(musicNotes)
, 'progress' -> 0, 'taskid' -> global_playListCounter});
), 'exception', (
return(null);
))
);
playScore(p, taskid) -> (
scoreInfo = global_playList:p;
if (scoreInfo == null || scoreInfo:'taskid' != taskid, (
return();
));
display_title(entity_selector(str(
'@e[type=player,distance=..5,x=%d,y=%d,z=%d]', p:0, p:1, p:2))
, 'actionbar', format('by ♬: ' + scoreInfo:'title'));
ct = tick_time();
st = scoreInfo:'start';
note_n = scoreInfo:'length';
progressPtr = scoreInfo:'progress';
while(progressPtr < note_n && scoreInfo:'notes':progressPtr:0 <= ct - st, (
sound('block.note_block.' + scoreInfo:'notes':progressPtr:2, p
, scoreInfo:'notes':progressPtr:1, scoreInfo:'notes':progressPtr:3
, 'record');
progressPtr += 1;
));
put(scoreInfo:'progress', progressPtr);
if (progressPtr >= note_n, (
delete(global_playList:p);
), (
schedule(scoreInfo:'notes':progressPtr:0 - (ct - st), 'playScore', p, taskid);
));
);
__on_player_clicks_block(me, b, f) -> (
if(b == 'sea_lantern', (
delete(global_playList, pos(b));
scoreInfo = parseScoreBook(inventory_get(me, query(me, 'selected_slot')));
if(scoreInfo == null, return());
put(scoreInfo, 'start', tick_time());
put(global_playList, pos(b), scoreInfo);
schedule(0, 'playScore', pos(b), scoreInfo:'taskid');
return('cancel');
));
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment