Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Drain, corresponding brush and new flag #51

Merged
merged 12 commits into from
Mar 21, 2021
3 changes: 3 additions & 0 deletions docs/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Left clicking again will reselect the whole box.
- `/world-edit paste [pos]` -> Pastes selection relative to player position or to `[pos]`, if given. Be careful incase you didnt' choose a wise spot making the selection.
- `/world-edit flood <block>` -> Performs a flood fill (fill connex volume) within the selection and starting at the player's position. Can both "fill" used to be air or replace some other block.
- `/world-edit flood <block> [axis]` -> Flood fill will happen only perpendicular to iven axis. Setting axis to `y`, for isntance, will fill the horizontal plane.
- `/world-edit drain [radius]` -> Drains the liquid the player is standing on. By default, it does so on a given radius, ut you can set that with the optional parameter. If you don't specify a radius and are standing in a seleciton, it will drain within the selection only. It supports the `-g` flag, try it!
- `/world-edit walls <block> [sides] [replacement]` -> Creates walls on the sides specified around the selection, defalts to ony vertical walls (`xz`).
- `/world-edit outline <block> [replacement]` -> Outlines the selection with `<block>`.
- `/world-edit shape ...` -> Generates a shape centered arround the palyer. See brushes for all options and parameters.
Expand All @@ -83,6 +84,7 @@ The available actions for brushes are:
- `prism_star <block> <outer_radius> <inner_radius> <height> <vertices> [axis] [rotation] [replacement]` -> generates a star whouse points touch a circle of radius `outer_radius` with `vertices` ammount of points. Said star is the base for a prism of height `height` along `axis`. Optionally, it can be rotated from it's base orientation.
- `line <block> [length] [replacement]` -> creates a line out of `block` between the player and the clicked block, replacing only blocks that match `replacement` (block or tag), if given. If `length` is given, the length of the line is fixed and it only uses the clicked block to get the direction of the line.
- `flood <block> <radius> [axis]` -> creates a flood fill starting in the target block and modifying all the connex blocks to become `block`, always staying within `radius` blocks of the starting point. The flood happens in the plane perpendicular to `axis`, if given.
- `drain <radius>` -> Drains the liquids connected to the liquid block you click, up to `<radius>` blocks away.
- `paste` -> pastes the current clipboard, using the targeted block as origin.
- `feature <fearure>` -> places a feature (decoration) in the targeted location. Can fail, if natural feature would fail. DOES NOT SUPPORT `undo` functionality.

Expand All @@ -107,3 +109,4 @@ Available flags:
- `-s` -> Preserves block states when seting blocks
- `-g` -> When replacing air or water, greenery corresponding to each medium will be replaced too
- `-h` -> When creating a shape, makes it hollow
- `-l` -> When used to register a brush, the brush will targer liquids as well as blocks, instead of going right through them to the block behind.
115 changes: 98 additions & 17 deletions world-edit.sc
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ base_commands_map = [
['move <pos>', ['move',null], [-1, 'help_cmd_move', null, null]],
['move <pos> f <flag>', 'move', false], //TODO flags help
['copy clear_clipboard',_()->(global_clipboard=[];_print(player(),'clear_clipboard',player())),[-1,'help_cmd_clear_clipboard',null,null]],
['copy',['_copy',null, false],[-1,'help_cmd_copy',null,null]],
['copy',['_copy',null, false],false],
['copy force',['_copy',null, true],false],
['copy <pos>',['_copy', false],false],
['copy <pos>',['_copy', false],[-1,'help_cmd_copy','help_cmd_copy_tooldtip',null]],
['copy <pos> force',['_copy', true],false],
['paste',['paste', null, null],[-1,'help_cmd_paste',null,null]],
['paste f <flag>',_(flags)->paste(null, flags),false],//todo flags help
Expand All @@ -60,6 +60,10 @@ base_commands_map = [
['flood <block> <axis>', ['flood_fill', null], [1, 'help_cmd_flood', 'help_cmd_flood_tooltip', null]],
['flood <block> f <flag>', _(block,flags)->flood_fill(block,null,flags), false],
['flood <block> <axis> f <flag>', 'flood_fill', false],
['drain', ['_drain', null, null], false],
['drain <radius>', ['_drain', null], [1, 'help_cmd_drain', 'help_cmd_drain_tooltip', null]],
['drain f <flag>', _(flag)->_drain(null, flag), false],
['drain <radius> f <flag>', '_drain', false],
['brush clear', ['brush', 'clear', null], [-1, 'help_cmd_brush_clear', null, null]],
['brush list', ['brush', 'list', null], [-1, 'help_cmd_brush_list', null, null]],
['brush info', ['brush', 'info', null], [-1, 'help_cmd_brush_info', null, null]],
Expand Down Expand Up @@ -148,6 +152,10 @@ base_commands_map = [
['brush prism_star <block> <outer_radius> <inner_radius> <height> <vertices> <axis> <degrees> <replacement> f <flag>',
_(block, outer_radius, inner_radius, height, n_points, axis, rotation, replacement, flags) -> brush('prism_star', flags, block, outer_radius, inner_radius, height, n_points, axis, rotation, replacement), false],
['brush feature <feature> ', _(feature) -> brush('feature', null, feature), [-1, 'help_cmd_brush_feature', 'help_cmd_brush_generic', null]],
['brush drain', _()->brush('drain', null, 30), false],
['brush drain <radius>', _(radius)->brush('drain', null, radius), [0, 'help_cmd_brush_drain', 'help_cmd_brush_generic', null]],
['brush drain f <flag>', _(flag)->brush('drain', flag, 30), false],
['brush drain <radius> f <flag>', _(radius, flag)->brush('drain', flag, radius), [0, 'help_cmd_brush_drain', 'help_cmd_brush_generic', null]],

['shape cube <block> <size>', _(block, size_int) -> cube(player()~'pos', [block, size_int, null], null), false],
['shape cube <block> <size> f <flag>', _(block, size_int, flags) -> cube(player()~'pos', [block, size_int, null], flags), false],
Expand Down Expand Up @@ -323,7 +331,8 @@ global_clipboard = [];

global_debug_rendering = false;
global_reach = 4.5;

global_default_trace_type = 'blocks';
global_liquid_trace_type = 'liquids';

//Extra boilerplate

Expand Down Expand Up @@ -454,7 +463,7 @@ selection_move(amount, direction) ->
point2 = _get_marker_position(global_selection:'to');
p = player();
if (p == null && direction == null, _error(player, 'move_selection_no_player_error'));
translation_vector = if(direction == null, get_look_direction(p)*amount, pos_offset([0,0,0],direction, amount));
translation_vector = if(direction == null, p~'look'*amount, pos_offset([0,0,0],direction, amount));
clear_markers(global_selection:'from', global_selection:'to');
point1 = point1 + translation_vector;
point2 = point2 + translation_vector;
Expand Down Expand Up @@ -488,25 +497,33 @@ __on_tick() ->
if (p = player(),
// put your catchall checks here
global_highlighted_marker = null;
reach = if( (held = p~'holds':0)==global_wand, global_reach, has(global_brushes, held), global_brush_reach);
reach = if(
(held = p~'holds':0)==global_wand, global_reach,
has(global_brushes, held), brush=true; global_brush_reach
);
if(brush && length(global_selection)<2, clear_selection());
new_cursor = if ( reach && p~'gamemode'!='spectator',
// support for tracing liquids with brushes
global_trace_type = if(has(global_liquid_brush, held), global_liquid_trace_type, global_default_trace_type);
// get traced block
if (marker = _trace_marker(p, global_reach),
global_highlighted_marker = marker;
_get_marker_position(marker)
,
_get_player_look_at_block(p, reach) )
);
// delete old marker if new one isn't the same
if (global_cursor && new_cursor != global_cursor,
draw_shape('box', 0, 'from', global_cursor, 'to', global_cursor+1, 'fill', 0xffffff22);
);
// render new marker or refresh old one
if (new_cursor,
draw_shape('box', 50, 'from', new_cursor, 'to', new_cursor+1, 'fill', 0xffffff22);
);
global_cursor = new_cursor;
)
);


__on_player_swings_hand(player, hand) ->
(
if(player~'holds':0==global_wand,
Expand Down Expand Up @@ -618,7 +635,7 @@ _render_selection_tick() ->

_get_player_look_at_block(player, range) ->
(
block = query(player, 'trace', range, 'blocks');
block = query(player, 'trace', range, global_trace_type);
if (block,
pos(block)
,
Expand Down Expand Up @@ -665,7 +682,7 @@ _set_or_give_wand(wand) -> (
)
);

global_flags = ['w','a','e','h','u','b','p','d','s','g'];
global_flags = ['w','a','e','h','u','b','p','d','s','g','l'];

//FLAGS:
//w waterlog block if previous block was water(logged) too
Expand All @@ -678,7 +695,7 @@ global_flags = ['w','a','e','h','u','b','p','d','s','g'];
//d "dry" out the pasted structure (remove water and waterlogged)
//s keep block states of replaced block, if new block matches
//g when replacing air or water, some greenery gets repalced too

//l when used in a brush, the brush will trace for liquids as well as blocks

_parse_flags(flags) ->(
if(!flags, return({}));
Expand Down Expand Up @@ -761,6 +778,14 @@ global_lang_keys = global_default_lang = {
'help_cmd_expand' -> 'l Expands sel [magn] from pos', //This is not understandable
'help_cmd_expand_tooltip' -> 'g Expands the selection [magnitude] from [pos]',
'help_cmd_move' -> 'l Moves selection to <pos>',
'help_cmd_clear_clipboard' -> 'l Clears current clipboard',
'help_cmd_copy' -> 'l Copy current selection to clipboard',
'help_cmd_copy_tooldtip' -> 'g Uses [pos] or player position as origin for the copied structure',
'help_cmd_paste' -> 'l Paste clipboard',
'help_cmd_drain' -> 'l Drains liquid you are standing on',
'help_cmd_drain_tooltip' -> 'g Acts in a radius or withing the selection',
'help_cmd_flood' -> 'l Perferoms a 3D flood fill out of [block]',
'help_cmd_flood_tooltip' -> 'g Use [axis] to make a flat fill',
'help_cmd_brush_clear' -> 'l Unregisters current item as brush',
'help_cmd_brush_list' -> 'l Lists all currently regiestered brushes and their actions',
'help_cmd_brush_info' -> 'l Gives detailed info of currently held brush',
Expand Down Expand Up @@ -842,6 +867,7 @@ global_lang_keys = global_default_lang = {
'action_stack' -> 'stack',
'action_expand' -> 'expand',
'action_paste' -> 'paste',
'action_drain' -> 'drain',
};
task(_()->write_file('langs/en_us','json',global_default_lang)); // Make a template for translators. Async cause why not. Maybe make an async section at the bottom?

Expand Down Expand Up @@ -913,6 +939,7 @@ _error(player, key, ... replace)->
// Brush

global_brushes = {};
global_liquid_brush = {};
global_brush_reach = 100;

brush(action, flags, ...args) -> (
Expand All @@ -923,7 +950,8 @@ brush(action, flags, ...args) -> (
if(
action=='clear',
if(has(global_brushes, held_item),
delete(global_brushes, held_item),
delete(global_brushes, held_item);
delete(global_liquid_brush, held_item),
_error(player, 'no_brush_error', held_item)
),
action=='list', //TODO imprvove list with interactiveness
Expand Down Expand Up @@ -952,7 +980,8 @@ brush(action, flags, ...args) -> (
);
global_brushes:held_item = [action, args, flags];

if(action=='feature', print(player, format('d Beware, placing features is very experimental and doesn\'t have support for the undo function')))
if(action=='feature', print(player, format('d Beware, placing features is very experimental and doesn\'t have support for the undo function')));
if(action=='drain' || _parse_flags(flags)~'l', global_liquid_brush+=held_item) // to change trace method
)
);

Expand Down Expand Up @@ -1098,7 +1127,7 @@ flood(pos, args, flags) -> (
_sq_distance(pos, start) <= radius*radius
);

_flood_generic(block, axis, start, flags);
_flood_generic(block, axis, start, _parse_flags(flags));
);

line(pos, args, flags) -> (
Expand Down Expand Up @@ -1275,6 +1304,11 @@ feature(pos, args, flags) -> (
plop(pos, what)
);

drain(pos, args, flags) -> (
[radius] = args;
_drain_generic(pos, radius, flags)
);

//Command processing functions

global_water_greenery = {'seagrass', 'tall_seagrass', 'kelp_plant'};
Expand Down Expand Up @@ -1625,13 +1659,12 @@ flood_fill(block, axis, flags) ->
_flood_tester(pos, outer(min_pos), outer(max_pos)) -> (
all(pos, _ >= min_pos:_i) && all(pos, _ <= max_pos:_i)
);
_flood_generic(block, axis, start, flags);
_flood_generic(block, axis, start, _parse_flags(flags));

);

_flood_generic(block, axis, start, flags) ->
(

// Define function to request neighbours perpendiular to axis
if(
axis==null, flood_neighbours(block) -> map(neighbours(block), pos(_)),
Expand All @@ -1641,12 +1674,25 @@ _flood_generic(block, axis, start, flags) ->
);

interior_block = block(start);

_is_interior(block, outer(interior_block)) -> block==interior_block;
// If flag -g is set, treat greenery as interior
if(flags~'g',
if(
interior_block == 'air',
print('is_air');
_is_interior(block) -> (air(block) || has(global_air_greenery, str(block))),
interior_block == 'water',
_is_interior(block) -> (block=='water' || has(global_water_greenery, str(block))),
)
);

if(_flood_tester(start), set_block(start, block, null, flags, {}), return());

visited = {start->null};
queue = [start];

while(length(queue)>0, 10000,
while(length(queue)>0, 100000,

current_pos = queue:0;
delete(queue, 0);
Expand All @@ -1655,9 +1701,9 @@ _flood_generic(block, axis, start, flags) ->
current_neighbour = _;
// check neighbours, add the non visited ones to the visited set
if(!has(visited, current_neighbour),
visited:current_neighbour = null;
visited += current_neighbour;
// if the block is not too far and is interior, delete it and add to queue to check neighbours later
if( block(_)==interior_block && _flood_tester(_),
if( _is_interior(block(_)) && _flood_tester(_),
queue:length(queue) = current_neighbour;
set_block(current_neighbour, block, null, flags, {})
);
Expand All @@ -1668,6 +1714,41 @@ _flood_generic(block, axis, start, flags) ->
add_to_history('action_flood', player())
);

_drain(radius, flags) -> _drain_generic(player()~'pos', radius, flags);

_drain_generic(pos, radius, flags) -> (
player = player();
if( (start_bl = block(pos)) == 'lava' || start_bl == 'water',

flags = _parse_flags(flags);
start = pos;

// check if inside selection, if there is a selection
if( length(global_selection) < 2,
no_selection = true,
// else, there is a selection
no_selection = false;
[pos1,pos2]=_get_current_selection(player);
min_pos = map(pos1, min(_, pos2:_i));
max_pos = map(pos1, max(_, pos2:_i));
// test if inside selection
_is_inside_selection(pos, outer(min_pos), outer(max_pos)) -> (
all(pos, _ >= min_pos:_i) && all(pos, _ <= max_pos:_i)
);
);

if( !no_selection && radius==null && _is_inside_selection(pos),
_flood_tester(pos)->_is_inside_selection(pos),
if(radius==null, radius=25);
_flood_tester(pos, outer(start), outer(radius)) -> _sq_distance(pos, start) <= radius*radius
);
_flood_generic('air', null, start, flags);

add_to_history('action_drain', player)
);
);


rotate(centre, degrees, axis)->(
player=player();
[pos1,pos2]=_get_current_selection(player);
Expand Down