// 计分板模块扩展插件 // 忽略假人分数 // **请勿修改文件名!!** //** 工具函数 **// contains(list, value) -> ( return(list ~ value != null); ); debug(msg) -> ( logger('debug', msg); return(); ); require_not_null(value) -> ( if(value == null, throw('空指针异常!')); return(value); ); require_version(requirement) -> ( req_0 = slice(requirement, 0, 1); req_1 = slice(requirement, 1, 2); if(req_0 == '>', if(req_1 == '=', req_ver = split('>=|\\.', requirement); print(player('all'), req_ver); cur_ver = split('\\.', global_carpet_version); return(number(req_ver:1) >= number(cur_ver:0) && number(req_ver:2) >= number(cur_ver:1) && number(req_ver:3) >= number(cur_ver:2)); ); req_ver = split('>|\\.', requirement); print(player('all'), req_ver); cur_ver = split('\\.', global_carpet_version); return(number(req_ver:1) > number(cur_ver:0) && number(req_ver:2) > number(cur_ver:1) && number(req_ver:3) > number(cur_ver:2)); ); if(req_0 == '<', if(req_1 == '=', req_ver = split('<=|\\.', requirement); print(player('all'), req_ver); cur_ver = split('\\.', global_carpet_version); return(number(req_ver:1) <= number(cur_ver:0) && number(req_ver:2) <= number(cur_ver:1) && number(req_ver:3) <= number(cur_ver:2)); ); req_ver = split('<|\\.', requirement); print(player('all'), req_ver); cur_ver = split('\\.', global_carpet_version); return(number(req_ver:1) < number(cur_ver:0) && number(req_ver:2) < number(cur_ver:1) && number(req_ver:3) < number(cur_ver:2)); ); return(false); ); //** 主要逻辑 **// global_app_name = system_info('app_name'); global_app_version = '1.1-beta.1'; global_carpet_version = split('\\+', system_info('scarpet_version')):0; global_current_scoreboard_list = [ 'fzsd.module.scoreboard.display.activation', 'fzsd.module.scoreboard.display.damage_taken', 'fzsd.module.scoreboard.display.death_count', 'fzsd.module.scoreboard.display.dig_count', 'fzsd.module.scoreboard.display.fishing_count', 'fzsd.module.scoreboard.display.kill_count', 'fzsd.module.scoreboard.display.trade_count', 'fzsd.module.scoreboard.display.bedrock_broken_count', 'fzsd.module.scoreboard.display.aviating_distance', 'fzsd.module.scoreboard.display.placement_count' ]; __config() -> { 'scope' -> 'global', 'requires' -> { 'carpet' -> '>=1.4.45', 'minecraft' -> '>=1.18' }, 'command_permission' -> 2, 'commands' -> { '' -> 'help', 'help' -> 'help', 'delete ' -> 'command_delete', 'update ' -> 'command_update', 'restore whitelist' -> ['command_restore', null, null], 'restore whitelist ' -> _(scoreboardID) -> command_restore(null, scoreboardID), 'restore player ' -> ['command_restore', null], 'restore player ' -> 'command_restore', 'restore whitelist ' -> _(custom, trade_count) -> command_restore_trade_count_confirm(custom, null, trade_count), 'restore player ' -> 'command_restore_trade_count_confirm', 'recalculate ' -> 'command_recalculate_total_score', 'recalculate' -> ['command_recalculate_total_score', null], 'commandPlayer ' -> 'carpet_command_player', 'reset ' -> 'command_reset', 'reset ' -> ['command_reset', null], 'set ' -> 'command_set' }, 'arguments' -> { 'trade_count' -> { 'type' -> 'term', 'suggest' -> ['fzsd.module.scoreboard.display.trade_count'] }, 'playerName' -> { 'type' -> 'term', 'suggester' -> _(args) -> player('all') }, 'scoreboardID' -> { 'type' -> 'term', 'suggest' -> global_current_scoreboard_list }, 'scoreboardPlayer' -> { 'type' -> 'term', 'suggester' -> _(args) -> get_scoreboard_player_list() }, 'permissionType' -> { 'type' -> 'term', 'suggest' -> [ 'true', 'false', 'ops' ] }, 'version' -> { 'type' -> 'term', 'suggest' -> [ '2.x', '3.0-beta.4', '3.0-beta.9', '3.0-beta.10' ] }, 'score' -> { 'type' -> 'int', 'suggest' -> [] }, 'custom' -> { 'type' -> 'term', 'suggest' -> [] } } }; __on_start() -> ( // 读取配置文件 global_config = read_file('config', 'json'); if(global_config == null, // carpet 1.4.69 兼容 global_config = {}; ); if(length(global_config) == 0, // 读取失败或不存在 delete_file('config', 'json'); // 避免一些意外的问题 global_config:'config_version' = '1.0.0'; // 占位用,无实际作用 if(require_version('>=1.99.99'), // 等待新功能支持 global_config:'allow_spawn_whitelist_player' = false; write_file('config', 'json', global_config); , // else write_file('config', 'json', global_config); ); ); global_team_cache = read_file('team_cache', 'json'); if(global_team_cache == null, // carpet 1.4.69 兼容 global_team_cache = {}; ); print(player('all'), 'fzsd_score.sc已加载!'); ); __on_close() -> ( delete_file('team_cache', 'json'); write_file('team_cache', 'json', global_team_cache); ); if(require_version('>=1.99.99'), // 等待新功能支持 __on_player_command(player, message) -> ( print(player('all'), 'command!'); if(length(message) > 7 && slice(message, 0, 7) == '/player' && !(global_config:'allow_spawn_whitelist_player'), return('cancel'); ); ); ); __on_player_connects(player) -> ( player_type = player ~ 'player_type'; player_team = player ~ 'team'; player_name = player ~ 'name'; if(player_type == 'fake', ( if(player_team != 'fzsd.module.scoreboard.fake', global_team_cache:player_name = player_team; ); team_add('fzsd.module.scoreboard.fake', player); print(player('all'), '↑假的'); ), player_type == 'shadow', ( if(player_team != 'fzsd.module.scoreboard.shadow', global_team_cache:player_name = player_team; ); team_add('fzsd.module.scoreboard.shadow', player); print(player('all'), '↑挂机'); ), try_restore_team_from_cache(player); ); ); __on_player_disconnects(player, reason) -> ( player_type = player ~ 'player_type'; if(player_type == 'fake' && player_team != 'fzsd.module.scoreboard.fake', ( print(player('all'), '↓假的'); ), player_type == 'shadow' && player_team != 'fzsd.module.scoreboard.shadow', ( print(player('all'), '↓挂机'); ) ); try_restore_team_from_cache(player); ); // 获取所有计分板下的所有玩家列表 get_scoreboard_player_list() -> ( set = m(); for(global_current_scoreboard_list, for(scoreboard(_), if(_ ~ '\\w', put(set:_, null); ); ); ); return(keys(set)); ); // 重置玩家计分板分数 command_reset(player, scoreboard) -> ( if(scoreboard == null, for(scoreboard(), scoreboard_remove(_, player); ); command_recalculate_total_score(null); print('已重置' + player + '的所有分数'); return(); ); scoreboard_remove(scoreboard, player); command_recalculate_total_score(scoreboard); print('已重置' + player + '的' + scoreboard + '分数'); return(); ); // 尝试从缓存恢复玩家队伍,玩家/假人上下线时执行 try_restore_team_from_cache(player) -> ( player_team = player ~ 'team'; player_name = player ~ 'name'; debug('restore_team_from_cache'); if(player_team == 'fzsd.module.scoreboard.fake' || player_team == 'fzsd.module.scoreboard.shadow', if(global_team_cache:player_name == null, ( team_leave(player); ), team_add(global_team_cache:player_name , player); delete(global_team_cache:player_name); ); ); ); help() -> ( print('暂未开发'); return(); ); // 删除旧版的计分板 command_delete(fzsd_version) -> ( if(fzsd_version == '3.0-beta.10', ( scoreboard_remove('fzsd.module.scoreboard.display.bedrock_broke_count'); ), fzsd_version == '3.0-beta.9', ( scoreboard_remove('fzsd.extra.bbl.display'); ), fzsd_version == '2.x', ( old_scoreboards = ['usedDiaAxe', 'usedDiaPickaxe', 'usedDiaShovel', 'usedDiaHoe', 'usedIroAxe','usedIroPickaxe', 'usedIroShovel', 'usedIroHoe', 'usedStoAxe', 'usedStoPickaxe', 'usedStoShovel', 'usedStoHoe', 'usedWooAxe', 'usedWooPickaxe', 'usedWooShovel', 'usedWooHoe', 'usedGolAxe', 'usedGolPickaxe', 'usedGolShovel', 'usedGolHoe', 'usedNetAxe', 'usedNetPickaxe', 'usedNetShovel', 'usedNetHoe', 'usedShears', 'damageTaken', '10xDamageTaken', 'deathCounter', 'deathTester', 'digCounter', 'fishingCounter', 'fishingTester', 'killCounter', 'tradingCounter', 'totalList', 'bedrockBreaked', 'fz.bbl', 'fz.aviate1m', 'fz.aviateCounter', 'fz.aviateOneTime', 'Health', 'carpetBot', 'parameter']; team_remove('carpetBot'); team_remove('shadowedPlayer'); for(old_scoreboards, scoreboard_remove(_)); ), fzsd_version == '3.0-beta.4', ( old_scoreboards = ['fz.module.scoreboard.display.activation', 'fz.module.scoreboard.display.damage_taken', 'fz.module.scoreboard.display.death_count', 'fz.module.scoreboard.display.dig_count', 'fz.module.scoreboard.display.fishing_count', 'fz.module.scoreboard.display.kill_count', 'fz.module.scoreboard.display.trade_count', 'fz.module.scoreboard.display.bedrock_broke_count', 'fz.module.scoreboard.display.aviating_distance', 'fz.module.scoreboard.display.placement_count', 'fz.module.scoreboard.assign.general', 'fz.module.scoreboard.display.general', 'fz.module.scoreboard.interactor']; team_remove('fz.module.scoreboard.fake'); team_remove('fz.module.scoreboard.shadow'); for(old_scoreboards, scoreboard_remove(_)); ), print('参数错误!'); return(); ); print('已清除旧版计分板!'); return(); ); // 从某一旧版升级 command_update(fzsd_version) -> ( if(fzsd_version == '3.0-beta.10', ( merge_score('fzsd.module.scoreboard.display.bedrock_broke_count', 'fzsd.module.scoreboard.display.bedrock_broken_count', fzsd_version); command_delete(fzsd_version); scoreboard_remove('fzsd.module.scoreboard.display.placement_count', '总放置方块数'); scoreboard_remove('fzsd.module.scoreboard.display.general', '总放置方块数'); ), fzsd_version == '3.0-beta.9', ( merge_score('fzsd.extra.bbl.display', 'fzsd.module.scoreboard.display.bedrock_broken_count', fzsd_version); command_delete(fzsd_version); ), fzsd_version == '2.x', ( params = [ ['activation', 'fzsd.module.scoreboard.display.activation'], ['damageTaken', 'fzsd.module.scoreboard.display.damage_taken'], ['deathCounter', 'fzsd.module.scoreboard.display.death_count'], ['digCounter', 'fzsd.module.scoreboard.display.dig_count'], ['fishingCounter', 'fzsd.module.scoreboard.display.fishing_count'], ['killCounter', 'fzsd.module.scoreboard.display.kill_count'], ['tradingCounter', 'fzsd.module.scoreboard.display.trade_count'], ['bedrockBreaked', 'fzsd.module.scoreboard.display.bedrock_broken_count'], ['fz.aviate1m', 'fzsd.module.scoreboard.display.aviating_distance'] ]; for(params, merge_score(..._, fzsd_version)); command_delete(fzsd_version); ), fzsd_version == '3.0-beta.4', ( params = [ ['fz.module.scoreboard.display.activation', 'fzsd.module.scoreboard.display.activation'], ['fz.module.scoreboard.display.damage_taken', 'fzsd.module.scoreboard.display.damage_taken'], ['fz.module.scoreboard.display.death_count', 'fzsd.module.scoreboard.display.death_count'], ['fz.module.scoreboard.display.dig_count', 'fzsd.module.scoreboard.display.dig_count'], ['fz.module.scoreboard.display.fishing_count', 'fzsd.module.scoreboard.display.fishing_count'], ['fz.module.scoreboard.display.kill_count', 'fzsd.module.scoreboard.display.kill_count'], ['fz.module.scoreboard.display.trade_count', 'fzsd.module.scoreboard.display.trade_count'], ['fz.module.scoreboard.display.bedrock_broke_count', 'fzsd.module.scoreboard.display.bedrock_broken_count'], ['fz.module.scoreboard.display.aviating_distance', 'fzsd.module.scoreboard.display.aviating_distance'], ['fz.module.scoreboard.display.placement_count', 'fzsd.module.scoreboard.display.placement_count'] ]; for(params, merge_score(..._, fzsd_version)); command_delete(fzsd_version); ), print('参数错误!'); return(); ); command_recalculate_total_score(null); print('已从' + fzsd_version + '升级!'); return(); ); // 将两计分板分数合并到后者 merge_score(from, to, fzsd_version) -> ( // 如果目标计分板不存在则创建 if(scoreboard() ~ to == null, scoreboard_add(to)); // new_players = []; if(fzsd_version == '2.x', ( // 2.x数据包的假人列表 fake_players = team_list('carpetBot'); // 新数据包的计分板中存储的玩家列表 new_players = scoreboard('fzsd.module.interactor.trigger'); for(fake_players, delete(new_players, _)); ), fzsd_version == '3.0-beta.4', ( new_players = scoreboard('fz.module.interactor.trigger'); ) ); for(scoreboard(from), if(!(_ ~ '\\W'), scoreboard(to, _, scoreboard(to, _) + scoreboard(from, _)); ); ); print('已合并:' + to); return(); ); // 获取承载总榜数据的玩家名 // 因为新计分板允许玩家自定义显示的总榜名称,故做复杂判断才能使脚本确定用来承载总榜数据的玩家名 get_total_score_name_new(scoreboard) -> ( INT_MIN = -2147483648; // 获取系统总榜id system_total_name = replace(scoreboard, 'display', 'total'); // 将系统总榜分数加上最小int值,使其成为最低分 scoreboard( 'fzsd.module.scoreboard.assign.general', system_total_name, scoreboard( 'fzsd.module.scoreboard.assign.general', system_total_name ) + INT_MIN ); // 将总分赋值到显示计分板上 display_total_score(scoreboard); // 查找显示计分板内的最低分玩家名 last_min_player = null; for(scoreboard(scoreboard), if(last_min_player == null, ( last_min_player = _; ), if(scoreboard(scoreboard, _) < scoreboard(scoreboard, last_min_player), last_min_player = _; ) ); ); // 恢复总榜分数 scoreboard( 'fzsd.module.scoreboard.assign.general', system_total_name, scoreboard( 'fzsd.module.scoreboard.assign.general', system_total_name ) - INT_MIN ); display_total_score(scoreboard); // 返回榜内最低分的玩家名(承载总榜数据的玩家名) return(last_min_player); ); // 重算总分,scoreboard == null 时重算所有总分 command_recalculate_total_score(scoreboard) -> ( if(scoreboard == null, for(global_current_scoreboard_list, command_recalculate_total_score(_)); return(); ); total_score_name_new = get_total_score_name_new(scoreboard); // 计算总分 total_score = 0; for(scoreboard(scoreboard), if(_ != total_score_name_new, total_score += scoreboard(scoreboard, _); ); ); // 赋值总分到系统总分计分板 scoreboard( 'fzsd.module.scoreboard.assign.general', replace(scoreboard, 'display', 'total'), total_score ); display_total_score(scoreboard); return(); ); // 使用数据包函数标签将总分赋值到显示计分板上 display_total_score(scoreboard) -> ( // 获取计算总榜的函数标签名 str_1 = split('\\.', scoreboard); function_name = str_1:(length(str_1) - 1); // 运行函数,将分数赋值到显示计分板上 run('function #fzsd:module/scoreboard/assign/scoreboard/general/' + function_name); return(); ); // 恢复计分板分数,player == null 时恢复所有玩家分数,scoreboard == null 时恢复所有计分板分数 command_restore(player, scoreboard) -> ( if(player == null, i = 0; for(keys(system_info('server_whitelist')), i += 1; if(i > 10, game_tick(50); i = 0; ); restore_score(_, scoreboard); ); if(scoreboard == null, ( print('重置交易榜会丢失猪灵交易分数,请输入\n“/' + global_app_name + ' restore confirm whitelist fzsd.module.scoreboard.display.trade_count”继续执行'); print('无法还原破基岩榜,已忽略'); print('已恢复所有玩家的所有分数'); ), if(scoreboard == 'fzsd.module.scoreboard.display.trade_count', print('重置交易榜会丢失猪灵交易分数,请输入\n“/' + global_app_name + ' restore confirm whitelist fzsd.module.scoreboard.display.trade_count”继续执行'); , scoreboard == 'fzsd.module.scoreboard.display.bedrock_broken_count', print('无法还原破基岩榜,已忽略'); , print('已恢复所有玩家的' + scoreboard + '分数'); ); ); return(); ); if(scoreboard == null, for(global_current_scoreboard_list, restore_score(player, _)); print('重置交易榜会丢失猪灵交易分数,请输入\n“/' + global_app_name + ' restore confirm player fzsd.module.scoreboard.display.trade_count”继续执行'); print('无法还原破基岩榜,已忽略'); print('已恢复' + player + '的所有分数'); return(); ); if(restore_score(player, scoreboard), print('已恢复' + player + '的' + scoreboard + '分数'); , if(scoreboard == 'fzsd.module.scoreboard.display.trade_count', print('重置交易榜会丢失猪灵交易分数,请输入\n“/' + global_app_name + ' restore confirm whitelist fzsd.module.scoreboard.display.trade_count”继续执行'); , scoreboard == 'fzsd.module.scoreboard.display.bedrock_broken_count', print('无法还原破基岩榜,已忽略'); ); ); return(); ); // 恢复玩家的计分板分数 restore_score(player_name, scoreboard) -> ( require_not_null(player_name); if(scoreboard == null, for(global_current_scoreboard_list, restore_score(player_name, _)); return(); ); player = player(player_name); player_is_offline = false; if(player == null, ( run('player ' + player_name + ' spawn at ~ ~ ~ facing 0 0 in minecraft:overworld in survival'); player_is_offline = true; player = player(player_name); ) ); if(scoreboard == 'fzsd.module.scoreboard.display.activation', ( play_ticks = statistic(player, 'custom', 'play_time'); scoreboard('fzsd.event.play_ticks', player, play_ticks%72000); scoreboard(scoreboard, player, play_ticks/72000); ), scoreboard == 'fzsd.module.scoreboard.display.damage_taken', scoreboard(scoreboard, player, statistic(player, 'custom', 'damage_taken')/10); , scoreboard == 'fzsd.module.scoreboard.display.death_count', restore_from_stat(scoreboard, player, 'custom', 'deaths'); , scoreboard == 'fzsd.module.scoreboard.display.dig_count', ( scoreboard(scoreboard, player, 0); for(block_list(), append_from_stat(scoreboard, player, 'mined', _); ); ), scoreboard == 'fzsd.module.scoreboard.display.fishing_count', scoreboard(scoreboard, player, statistic(player, 'custom', 'fish_caught')); , scoreboard == 'fzsd.module.scoreboard.display.kill_count', ( scoreboard(scoreboard, player, 0); for(entity_types('living'), append_from_stat(scoreboard, player, 'killed', _); ); ), scoreboard == 'fzsd.module.scoreboard.display.trade_count', return(false); , scoreboard == 'fzsd.module.scoreboard.display.bedrock_broken_count', return(false); , scoreboard == 'fzsd.module.scoreboard.display.aviating_distance', scoreboard(scoreboard, player, statistic(player, 'custom', 'aviate_one_cm')/200); , scoreboard == 'fzsd.module.scoreboard.display.placement_count', ( scoreboard(scoreboard, player, 0); for(block_list(), append_from_stat(scoreboard, player, 'used', _); ); ), print('未识别的计分板ID!' + scoreboard); return(false); ); command_recalculate_total_score(scoreboard); if(player_is_offline, world_spawn = system_info('world_spawn_point'); run('spreadplayers ' + world_spawn:0 + ' ' + world_spawn:2 + ' 0 10 false ' + player); run('player ' + player + ' kill'); ); return(true); ); // 确定恢复交易榜 command_restore_trade_count_confirm(confirm, player, trade_count) -> ( if(confirm != 'confirm' || trade_count != 'fzsd.module.scoreboard.display.trade_count', print('命令格式错误!'); return(); ); if(player == null, for(keys(system_info('server_whitelist')), restore_from_stat(scoreboard, _, 'custom', 'traded_with_villager'); ); return(); ); restore_from_stat(scoreboard, player, 'custom', 'traded_with_villager'); return(); ); restore_from_stat(scoreboard, player, category, entry) -> ( scoreboard(scoreboard, player, statistic(player, category, entry)); ); append_from_stat(scoreboard, player, category, entry) -> ( scoreboard(scoreboard, player, statistic(player, category, entry) + scoreboard(scoreboard, player) ); ); // 修改地毯假人规则 carpet_command_player(level) -> ( print(run('carpet setDefault commandPlayer ' + level):1:0); return(); ); // 设置玩家的计分板分数 command_set(player, scoreboard, score) -> ( i = scoreboard(scoreboard, player, score); print('玩家' + player + '修改前的分数为:' + i); command_recalculate_total_score(scoreboard); return(i); );