From 267c3c0788e0a87eaa3533ed6173551772ec6114 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 15 Aug 2020 02:33:03 -0300 Subject: [PATCH] added ai_tracker built-in app --- .../carpet/script/CarpetScriptServer.java | 1 + .../assets/carpet/scripts/ai_tracker.sc | 482 ++++++++++++++++++ 2 files changed, 483 insertions(+) create mode 100644 src/main/resources/assets/carpet/scripts/ai_tracker.sc diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 569a2728..f9e5d765 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -59,6 +59,7 @@ public class CarpetScriptServer registerBuiltInScript(BundledModule.carpetNative("stats_test", false)); registerBuiltInScript(BundledModule.carpetNative("math", true)); registerBuiltInScript(BundledModule.carpetNative("chunk_display", false)); + registerBuiltInScript(BundledModule.carpetNative("ai_tracker", false)); } public CarpetScriptServer(MinecraftServer server) diff --git a/src/main/resources/assets/carpet/scripts/ai_tracker.sc b/src/main/resources/assets/carpet/scripts/ai_tracker.sc new file mode 100644 index 00000000..08be77a2 --- /dev/null +++ b/src/main/resources/assets/carpet/scripts/ai_tracker.sc @@ -0,0 +1,482 @@ +__command() -> ' +ai_tracker allows to display +some extra information about +various entities AI activity + +WIP - more options and settings will be +added in the future + +Current supported actions + - current selected paths for all living entities + - movement speeds per block and coordinate + - item pickup range + - buddy villager detection for villagers + - hostile detection for villagers + - iron golem spawning for villagers + - breeding info for villagers + +Settings you may want to change + - toggle_boxes: hides/shows large boxes and spheres + - update_frequency: changes update speed + - clear: removes all options + - transparency: default opacity of shapes, 8 for start +'; + + +global_duration = 12; +global_interval = 10; + +global_opacity = 8; + +global_display_boxes = true; + + + +global_range = 48; + +// list of triples - [entity_type, feature, callback] +global_active_functions = []; +global_feature_switches = {}; +global_tracker_running = false; + +villager_iron_golem_spawning() -> __toggle('villager_iron_golem_spawning', null); +pathfinding() -> __toggle('pathfinding', null); +velocity() -> __toggle('velocity', null); +villager_breeding() -> __toggle('villager_breeding', null); +villager_buddy_detection() -> __toggle('villager_buddy_detection', null); +item_pickup() -> __toggle('item_pickup', null); + + +toggle_boxes() -> +( + global_display_boxes = !global_display_boxes; + ''; +); + +update_frequency(ticks) -> +( + if (type(ticks) != 'number' || ticks <=0 || ticks > 100, exit('Ticks needs to be a positive number from 1 to 100')); + global_interval = ticks; + global_duration = ticks + 2; + ''; +); + +transparency(alpha) -> +( + if (type(alpha) != 'number' || alpha <=0 || alpha > 255, exit('Ticks needs to be a number from 0 to 255')); + global_opacity = floor(alpha); + ''; +); + + + +villager_hostile_detection(hostile) -> +( + if (!has(global_hostile_to_villager:hostile), + print(player(), 'Unknown hostile that affects villagers, possible options are: '+keys(global_hostile_to_villager)); + exit(''); + ); + __toggle('villager_hostile_detection', hostile); +); + +global_entity_positions = {}; + +global_functions = { + 'villager_iron_golem_spawning' -> { + 'villager' -> [ + _(arg) -> _(e) -> ( + abnoxious_visuals = []; + visuals = []; + half_width = e~'width'/2; + villager_height = e~'height'; + __create_box(abnoxious_visuals, e, + [-8,-6,-8], + [8,7,8], + 0x00dd0000, 'golem spawning', true + ); + __create_box(abnoxious_visuals, e, + [-16-half_width,-16,-16-half_width], + [16+half_width,16+height,16+half_width], + 0xdddddd00, 'golem detection', false + ); + + last_seen = 0; + entry = query(e, 'brain', 'golem_detected_recently'); + if (entry, last_seen = entry:1); + + if (last_seen, + mobs = query(e, 'brain', 'mobs'); + if(mobs, for(filter(mobs, _ ~'type' == 'iron_golem'), + w = _~'width'/2; + __outline_mob(visuals, _, 0xee000000, 'in range', 0.5); + visuals+=['line', global_duration, 'from', pos(e), 'to', pos(_), 'color', 0xddddddff]; + )); + ); + + + entry = query(e, 'brain', 'last_slept'); + slept = world_time()-entry; + last_slept = format(if(entry == null, 'rb never', if(slept < 24000, 'e ', 'y ')+slept)); + + labels = [ + ['golem timer', 'golem:', format(if(last_seen,'rb ','eb ')+last_seen )], + ['sleep tracker', 'slept:', last_slept], + ['attempt', 'attempt in:', format(if( slept < 24000 && last_seen==0,'yb ','gi ')+ (100-(world_time()%100)))], + ]; + [visuals, abnoxious_visuals, labels]; + ) + , + null + ] + }, + 'villager_buddy_detection' -> { + 'villager' -> [ + _(arg) -> _(e) -> ( + visuals = []; + abnoxious_visuals = []; + half_width = e~'width'/2; + height = e~'height'; + __create_box(abnoxious_visuals, e, + [-10-half_width,-10,-10-half_width], + [10+half_width,10+height,10+half_width], + 0x65432100, 'buddy detection', false + ); + [x,y,z] = pos(e); + current_id = e~'id'; + buddies = entity_area('villager', x, y+height/2, z, 10+half_width, 10+height/2, 10+half_width); + nb = length(buddies); + for (filter(buddies, _~'id' != current_id), + visuals+=['line', global_duration, 'from', pos(e), 'to', pos(_), 'color', 0xffff00ff]; + ); + [visuals, abnoxious_visuals, [['vill_seen', 'buddies: ', format(if(nb==3, 'eb ', nb > 3, 'yb ', 'rb ' )+nb)]]]; + ), + , + null + ] + }, + 'item_pickup' -> { + '*' -> [ + _(arg) -> _(e) -> ( + if (e~'type' == 'player', return([[],[],[]])); + visuals = []; + abnoxious_visuals = []; + half_width = e~'width'/2; + height = e~'height'; + __create_box(abnoxious_visuals, e, + [-1-half_width,0,-1-half_width], + [1+half_width, height,1+half_width], + 0xffff0000, 'item range', false + ); + [x,y,z] = pos(e); + for (filter(entity_area('item', x, y+height/2, z, 1+half_width, height/2, 1+half_width), pos(_) != pos(e)), + visuals+=['line', global_duration, 'from', pos(e)+[0,1,0], 'to', pos(_)+[0,0,0], 'color', 0xffff00ff] + ); + [visuals, abnoxious_visuals, []]; + ), + , + null + ] + }, + + 'villager_hostile_detection' -> { + 'villager' -> [ + _(hostile) -> _(e, outer(hostile)) -> ( + visuals = []; + abnoxious_visuals = []; + tags = []; + if (has(global_hostile_to_villager:hostile), + abnoxious_visuals += ['sphere', global_duration, 'center', [0,0,0], 'radius', global_hostile_to_villager:hostile, 'follow', e, + 'color', 0x88000055, 'fill', 0x88000000+global_opacity] + ); + mobs = query(e, 'brain', 'visible_mobs'); + if (mobs, + mob = query(e, 'brain', 'nearest_hostile'); + id = -1; + + if (mob, + __outline_mob(visuals, mob, 0xff000000, 'danger', 0.5); + visuals+=['line', global_duration, 'from', pos(e)+[0,e~'eye_height',0], 'to', pos(mob)+[0,mob~'eye_height',0], 'color', 0xff0000ff, 'line', 5]; + id = mob~'id'; + ); + other_hostile_mobs = filter(mobs, __is_hostile(e, _) && _~'id' != id); + for (other_hostile_mobs, + __outline_mob(visuals, _, 0xaa880000, 'detected', 0.7); + ); + tags += ['detection', 'hostile:', format( + if (mob, 'rb '+mob, other_hostile_mobs, 'y detected', 'e peaceful') + )]; + , + tags += ['detection', 'hostile:', format('e peaceful')] + ); + [visuals, abnoxious_visuals, tags]; + ), + , + null + ] + }, // ☖ ☽ ♨ ♡ + 'villager_breeding' -> { + 'villager' -> [ + _(arg) -> _(e) -> ( + visuals = []; + abnoxious_visuals = []; + + bed = query(e, 'brain', 'home'); + if (bed, + [dim, bed_pos] = bed; + same_dim = dim == e~'dimension'; + visuals += ['line', global_duration, + 'from', pos(e)+[0,1,0], 'to', if(same_dim, bed_pos+[0.5,0.5626,0.5], pos(e)+[0,3,0]), 'color', 0xffffaaff, 'line', 5]; + if (same_dim, + visuals += ['box', global_duration, 'from', bed_pos, 'to', bed_pos+[1, 0.5626, 1], 'color', 0xffffaacc, 'fill', 0xffffaa88] + ); + + ); + + food = __compute_food(e); + portions = floor(food / 12); + + breeding_age = e~'breeding_age'; + + + [visuals, abnoxious_visuals, [ + ['hasbed', 'bed: ', format(if(bed, 'be has home', 'br no home'))], // ☖ ☽ ♨ ♡ + ['hasfood', 'food: ', format(if(food, 'be '+portions+' portions', 'br 0 portions'))], + ['breeding', 'timer: ',format(if(breeding_age, 'be ', 'br ')+breeding_age)], + + ]]; + ), + , + _(arg) -> _(e, i) -> ( + item = i:0; + print(item); + if (item == 'rotten_flesh', + loop(inventory_size(e), + inventory_set(e, _, null); + ); + , + item ~ '^\\w+_bed$', + print('got bed') + ) + + ) + ] + }, + + 'velocity' -> { + '*' -> [ + _(arg) -> _(e) -> ( + id = e~'id'; + labels = []; + if (has(global_entity_positions:id), + cpos = pos(e); + ppos = global_entity_positions:id; + dpos = ppos-cpos; + dpos = dpos*20/global_interval; + labels += ['xvel', 'x speed:', str('%.3f',dpos:0)]; + labels += ['yvel', 'y speed:', str('%.3f',dpos:1)]; + labels += ['zvel', 'z speed:', str('%.3f',dpos:2)]; + ); + global_entity_positions:id = pos(e); + path = e ~ 'path'; + visuals = []; + if (path, for(path, __mark_path_element(_, visuals))); + [[], [], labels]; + ), + , + null + ] + }, + + 'pathfinding' -> { + '*' -> [ + _(arg) -> _(e) -> ( + path = e ~ 'path'; + visuals = []; + if (path, for(path, __mark_path_element(_, visuals))); + [visuals, [], []]; + ), + , + null + ] + }, +}; + +global_villager_food = { + 'bread' -> 4, + 'potato' -> 1, + 'carrot' -> 1, + 'beetroot' -> 1 +}; + +__compute_food(villager) -> +( + food = 0; + for (filter(inventory_get(villager), _), + val = global_villager_food:(_:0); + if (val, food += val*_:1); + ); + food; +); + +__outline_mob(visuals, e, color, caption, offset) -> +( + w = e~'width'/2; + visuals += ['box', global_duration, 'from', [-w,0,-w], 'to', [w, e~'height', w], 'follow', e, 'color', color+120, 'fill', color+global_opacity]; + visuals += ['label', global_duration, 'pos', [0, e~'height'+offset, 0], 'text', caption, 'follow', e, 'color', color+255]; +); + +__create_box(visuals, e, from, to, color, caption, discrete) -> +( + visuals += ['box', global_duration, 'from', from, 'to', to, + 'follow', e, 'snap', if(discrete, 'dxdydz', 'xyz'), 'color', color+255, 'fill', color+global_opacity]; + top_center = (from+to)/2; + top_center:1 = to:1+1; + visuals += ['line', global_duration, 'from', to, 'to', to+[1,2,1], + 'follow', e, 'snap', if(discrete, 'dxdydz', 'xyz'), 'color', color+255, 'line', 10]; + visuals += ['label', global_duration, 'pos', to+[1,2,1], 'text', caption, + 'follow', e, 'snap', if(discrete, 'dxdydz', 'xyz'), 'color', color+255 ]; + +); + +__mark_path_element(path_element, visuals) -> +( + [block, type, penalty, completed] = path_element; + color = if (penalty, 0x88000000, 0x00880000); + visuals += ['box', global_duration, + 'from', pos(block), 'to', pos(block)+[1,0.1+0.01*penalty,1], 'color', color+255, 'fill', color+global_opacity]; + if (penalty, + visuals += ['label', global_duration, 'pos', pos(block)+0.5, 'text', 'penalty', 'value', penalty, 'color', color+255] + ) +); + +global_hostile_to_villager = { + 'drowned' -> 8, + 'evoker'-> 12, + 'husk' -> 8, + 'illusioner' -> 12, + 'pillager' -> 15, + 'ravager' -> 12, + 'vex' -> 8, + 'vindicator' -> 10, + 'zoglin' -> 10, + 'zombie' -> 8, + 'zombie_villager' -> 8 +}; + +__is_hostile(v, m) -> +( + mob = m~'type'; + has(global_hostile_to_villager:mob) && (sqrt(reduce(pos(v)-pos(m), _a+_*_ , 0)) <= global_hostile_to_villager:mob) +); + +__distance(v1, v2) -> sqrt(reduce(v1-v2,_a+_*_ ,0)); + + + +__toggle(feature, arg) -> +( + if (has(global_feature_switches:feature) && global_feature_switches:feature == arg, + // disable + global_active_functions = filter(global_active_functions, _:1 != feature); + delete(global_feature_switches:feature); + , + //enable + // clean previous + global_active_functions = filter(global_active_functions, _:1 != feature); + + for(pairs(global_functions:feature), + global_active_functions += [_:0, feature, if (_:1:0, call(_:1:0, arg), null), if (_:1:1, call(_:1:1, arg), null)] + ); + global_feature_switches:feature = arg; + if (!global_tracker_running, + global_tracker_running = true; + __tick_tracker(); + ) + ); + __reset_interaction_types(); + ''; +); + +global_interaction_types = {}; + +__reset_interaction_types() -> +( + global_interaction_types = {}; + for (global_feature_switches, feature = _; + for ( filter(keys(global_functions:feature), global_functions:feature:_:1 != null ), + global_interaction_types += _; + if (_ == '*', return()); + ) + ); +); + +__on_player_interacts_with_entity(player, entity, hand) -> +( + if (hand == 'mainhand' && global_interaction_types && (has(global_interaction_types:(entity~'type')) || has(global_interaction_types:'*')), + for (global_active_functions, + if (_:3 != null && (_:0 == '*' || _:0 == entity~'type'), + call(_:3, entity, player~'holds') + ) + ) + ) +); + +clear() -> +( + global_active_functions = []; + global_feature_switches = {}; + '' +); + + + +__tick_tracker() -> +( + if (!global_active_functions, + global_tracker_running = false; + return() + ); + p = player(); + [px, py, pz] = pos(p); + for (entity_area('living', px, py, pz, global_range, global_range, global_range), + __handle_entity(_) + ); + schedule(global_interval, '__tick_tracker'); +); + +__handle_entity(e) -> +( + entity_type = e ~ 'type'; + shapes_to_display = []; + abnoxious_to_display = []; + labels_to_add = []; + for ( global_active_functions, + if (_:2 != null && (_:0 == '*' || _:0 == entity_type), + [shapes, abnoxious_shapes, labels] = call(_:2, e); + put(shapes_to_display, null, shapes, 'extend'); + if (global_display_boxes, put(abnoxious_to_display, null, abnoxious_shapes, 'extend');); + put(labels_to_add, null, labels, 'extend'); + ) + ); + + put(shapes_to_display, null, abnoxious_to_display, 'extend'); + + if (labels_to_add, + base_pos = [0.5, e~'height'+0.4, 0.5]; + base_height = 0; + for (labels_to_add, + if (length(_) == 2, + [label, text] = _; + shapes_to_display += ['label', global_duration, 'text', label, 'value', text, 'pos', base_pos, 'follow', e, 'height', base_height, 'snap', 'dxydz']; + , + [label, annot, value] = _; + shapes_to_display += ['label', global_duration, 'text', format('gi '+annot), 'pos', base_pos, 'follow', e, 'height', base_height, 'align', 'right', 'indent', -0.2, 'snap', 'dxydz']; + shapes_to_display += ['label', global_duration, 'text', label,'value', value, 'pos', base_pos, 'follow', e, 'height', base_height, 'align', 'left', 'snap', 'dxydz']; + ); + base_height += 1; + ); + ); + draw_shape(shapes_to_display); +); + +