added ai_tracker built-in app
This commit is contained in:
1 parent
eaded1450d
commit
267c3c0788
2 files changed
+483
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user