modernize camera.sc

This commit is contained in:
gnembon committed 2023-02-18 08:58:32 +01:00
1 parent bd0f47ff29
commit 65de5492ac
1 file changed
+185 -193
+185 -193
View File
@@ -1,75 +1,72 @@
_command() -> usage() -> 'camera: scarpet app.
( -------------------
print('camera: scarpet app.'); "/camera start" - Set the starting point, resetting the path
print('-------------------');
print(' "/camera start" - Set the starting point, resetting the path');
print('');
print(' "/camera add <N>" - Add a point to the end, <N> secs later');
print(' "/camera prepend <N>" - Prepend the start <N> secs before');
print(' "/camera clear" - Remove entire path');
print(' "/camera select" - .. a point or just punch it, to select it');
print(' "/camera place_player - Move player to the selected point');
print(' "/camera move" - Move the selected point to players location');
print(' "/camera duration <X>" - Set new selected path duration');
print(' "/camera split_point" - Split selected path in half.');
print(' "/camera delete_point" - Remove current key point');
print(' "/camera trim_path" - Remove all key points from selected up');
print('');
print(' "/camera save_as <name>"');
print(' "/camera load <name>"');
print(' - Store and load paths from world saves /scripts folder');
print('');
print(' "/camera interpolation < linear | gauss | catmull_rom | gauss <variance?> >"');
print(' Select interpolation between points:');
print(' - catmull_rom: Catmull-Rom interpolation (default).');
print(' smooth path that goes through all points.');
print(' - linear: straight paths between points.');
print(' - gauss: automatic smooth transitions.');
print(' - gauss <variance>: custom fixed variance ');
print(' (in seconds) for special effects.');
print(' gauss makes the smoothest path,');
print(' but treating points as suggestions only');
print('');
print(' "/camera repeat <N> <last_delay>" - ');
print(' Repeat existing points configuration n-times');
print(' using <last_delay> seconds to link path ends');
print('');
print(' "/camera stretch <factor (in %)>" - ');
print(' Change length of the entire path');
print(' from 25 -> 4x faster, to 400 -> 4x slower,');
print('');
print(' "/camera transpose" - ');
print(' Move entire path with the start at players position.');
print('');
print(' "/camera play : Run the path with the player');
print(' use "sneak" to stop it prematurely');
print(' run /camera hide and F1 to clear the view');
print('');
print(' "/camera show": Show current path particles');
print(' color of particles used is different for different players');
print(' "/camera hide": Hide path display');
print(' "/camera prefer_smooth_play": ');
print(' Eat CPU spikes and continue as usual');
print(' "/camera prefer_synced_play": ');
print(' After CPU spikes jump to where you should be');
print('');
null "/camera add <N>" - Add a point to the end, <N> secs later
); "/camera prepend <N>" - Prepend the start <N> secs before
__config() ->{ "/camera clear" - Remove entire path
'commands'->{ "/camera select" - .. a point or just punch it, to select it
''->'_command', "/camera place_player - Move player to the selected point
'<command>'->'_call', "/camera move" - Move the selected point to players location
'add <seconds>'->'add', "/camera duration <X>" - Set new selected path duration
'prepend <seconds>'->'prepend', "/camera split_point" - Split selected path in half.
"/camera delete_point" - Remove current key point
"/camera trim_path" - Remove all key points from selected up
"/camera save_as <name>"
"/camera load <name>"
- Store and load paths from world saves /scripts folder
"/camera interpolation < linear | gauss | catmull_rom | gauss <variance?> >"
Select interpolation between points:
- catmull_rom: Catmull-Rom interpolation (default).
smooth path that goes through all points.
- linear: straight paths between points.
- gauss: automatic smooth transitions.
- gauss <variance>: custom fixed variance
(in seconds) for special effects.
gauss makes the smoothest path,
but treating points as suggestions only
"/camera repeat <N> <last_delay>" -
Repeat existing points configuration n-times
using <last_delay> seconds to link path ends
"/camera stretch <factor (in %)>" -
Change length of the entire path
from 25 -> 4x faster, to 400 -> 4x slower,
"/camera transpose" -
Move entire path with the start at players position.
"/camera play : Run the path with the player
use "sneak" to stop it prematurely
run /camera hide and F1 to clear the view
"/camera show": Show current path particles
color of particles used is different for different players
"/camera hide": Hide path display
"/camera prefer_smooth_play":
Eat CPU spikes and continue as usual
"/camera prefer_synced_play":
After CPU spikes jump to where you should be
';
__config() -> {
'commands' -> {
'' -> _() -> print(usage()),
'<command>' -> '_call',
'add <seconds>' -> 'add',
'prepend <seconds>' -> 'prepend',
'duration <seconds>' -> 'duration', 'duration <seconds>' -> 'duration',
'save_as <name>'->'save_as', 'save_as <name>' -> 'save_as',
'load <name>'->'load', 'load <name>' -> 'load',
'interpolation <interpolation>'->['__interpolation',true], 'interpolation <interpolation>' -> ['interpolation', null, true],
'interpolation gauss'->['__interpolation','gauss',true], 'interpolation gauss' -> ['interpolation', 'gauss', null, true],
'interpolation gauss <seconds>'->_(float)->(__interpolation('gauss_'+str(float),true)), 'interpolation gauss <seconds>' -> _(float) -> interpolation('gauss', float, true),
'repeat <seconds> <last_delay>'->'repeat', 'repeat <seconds> <last_delay>' -> 'repeat',
'stretch <factor>'->'stretch' 'stretch <factor>' -> 'stretch'
}, },
'arguments'->{ 'arguments'->{
'seconds'->{'type'->'float', 'min' -> 0.01, 'suggest'->[]}, 'seconds'->{'type'->'float', 'min' -> 0.01, 'suggest'->[]},
@@ -119,14 +116,14 @@ global_color_b = null;
global_path_precalculated = null; global_path_precalculated = null;
// starts the path with current player location // starts the path with current player location
start() -> __start_with( _() -> l(l(__camera_position(), 0,'sharp')) ); start() -> _start_with( _() -> [ [_camera_position(), 0, 'sharp'] ] );
// start path with customized initial points selection // start path with customized initial points selection
__start_with(points_supplier) -> _start_with(points_supplier) ->
( (
p = player(); p = player();
global_player = str(p); global_player = str(p);
global_player_eye_offset = l(0, p~'eye_height',0,0,0); global_player_eye_offset = [0, p~'eye_height',0,0,0];
global_dimension = p~'dimension'; global_dimension = p~'dimension';
code = abs(hash_code(str(p))-123456); code = abs(hash_code(str(p))-123456);
@@ -135,13 +132,13 @@ __start_with(points_supplier) ->
global_points = call(points_supplier); global_points = call(points_supplier);
global_selected_point = null; global_selected_point = null;
__update(); _update();
show(); show();
print(str('Started path at %.1f %.1f %.1f', p~'x', p~'y', p~'z')); print(str('Started path at %.1f %.1f %.1f', p~'x', p~'y', p~'z'));
); );
// gets current player controlling the path, or fails // gets current player controlling the path, or fails
__get_player() -> _get_player() ->
( (
if (!global_player, exit('No player selected')); if (!global_player, exit('No player selected'));
p = player(global_player); p = player(global_player);
@@ -152,21 +149,21 @@ __get_player() ->
// clears current path // clears current path
clear() -> clear() ->
( (
global_points = l(); global_points = [];
global_dimension = null; global_dimension = null;
global_player = null; global_player = null;
global_selected_point = null; global_selected_point = null;
global_showing_path = false; global_showing_path = false;
global_playing_path = false; global_playing_path = false;
__update(); _update();
print('Path cleared'); print('Path cleared');
); );
// camera position for the player sticks out of their eyes // camera position for the player sticks out of their eyes
__camera_position() -> (__get_player()~'location' + global_player_eye_offset); _camera_position() -> (_get_player()~'location' + global_player_eye_offset);
// path changed, now notify all processes that they need to update; // path changed, now notify all processes that they need to update;
__update() -> _update() ->
( (
global_path_precalculated = null; global_path_precalculated = null;
global_playing_path = false; global_playing_path = false;
@@ -174,90 +171,86 @@ __update() ->
); );
// ensures that the current execution context can modify the path // ensures that the current execution context can modify the path
__assert_can_modify_path() -> _assert_can_modify_path() ->
( (
if (!global_points, exit('Path is not setup for current player')); if (!global_points, exit('Path is not setup for current player'));
if (!global_showing_path, exit('Turn on path showing to edit key points')); if (!global_showing_path, exit('Turn on path showing to edit key points'));
if(!global_player || !global_dimension || __get_player()~'dimension' != global_dimension, if(!global_player || !global_dimension || _get_player()~'dimension' != global_dimension,
exit('Player not in dimension')); exit('Player not in dimension'));
); );
// make sure selected point is correct // make sure selected point is correct
__assert_point_selected(validator) -> _assert_point_selected(validator) ->
( (
__assert_can_modify_path(); _assert_can_modify_path();
if (!call(validator, global_selected_point), exit('No appropriate point selected')); if (!call(validator, global_selected_point), exit('No appropriate point selected'));
); );
//select a custom interpolation method //select a custom interpolation method
__interpolation(method, verbose) -> interpolation(method, option, verbose) ->
( (
__prepare_path_if_needed() -> __prepare_path_if_needed_generic(); _prepare_path_if_needed() -> _prepare_path_if_needed_generic();
// each supported method needs to specify its __find_position_for_point to trace the path // each supported method needs to specify its _find_position_for_point to trace the path
// accepting segment number, and position in the segment // accepting segment number, and position in the segment
// or optionally __prepare_path_if_needed, if path is inefficient to compute point by point // or optionally _prepare_path_if_needed, if path is inefficient to compute point by point
global_interpolator = if ( global_interpolator = if (
method == 'linear', '__interpolator_linear', method == 'linear', '_interpolator_linear',
method == 'catmull_rom', '__interpolator_cr', method == 'catmull_rom', '_interpolator_cr',
method == 'gauss', _(s, p) -> __interpolator_gauB(s, p, 0), method == 'gauss' && option == null, _(s, p) -> _interpolator_gauB(s, p, 0),
method ~ '^gauss_', method == 'gauss',
( variance = round(60*option);
type = method - 'gauss_'; _(s, p, outer(variance)) -> _interpolator_gauB(s, p, variance);
type = replace(type,'_','.');
variance = round(60*number(type));
_(s, p, outer(variance)) -> __interpolator_gauB(s, p, variance);
)
); );
__update(); _update();
if(verbose, print('Interpolation changed to '+method)); if(verbose, print('Interpolation changed to '+method + if(option, ' '+option, '')));
); );
__interpolation('catmull_rom', false); interpolation('catmull_rom', null, false);
// adds a point to the end of the path with delay in seconds // adds a point to the end of the path with delay in seconds
add(delay) -> add(delay) ->
( (
__assert_can_modify_path(); _assert_can_modify_path();
//mode is currently unused, run_path does always sharp, gauss interpolator is always smooth //mode is currently unused, run_path does always sharp, gauss interpolator is always smooth
// but this option could be used could be used at some point by more robust interpolators // but this option could be used could be used at some point by more robust interpolators
__add_path_segment(__camera_position(), round(60*delay), 'smooth', true); _add_path_segment(_camera_position(), round(60*delay), 'smooth', true);
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// prepends the path with a new starting point, with a segment of specified delay // prepends the path with a new starting point, with a segment of specified delay
prepend(delay) -> prepend(delay) ->
( (
__assert_can_modify_path(); _assert_can_modify_path();
__add_path_segment(__camera_position(), round(60*delay), 'smooth', false); _add_path_segment(_camera_position(), round(60*delay), 'smooth', false);
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// repeats existing points seveal times, using last section delay (seconds) to join points // repeats existing points seveal times, using last section delay (seconds) to join points
repeat(times, last_section_delay) -> repeat(times, last_section_delay) ->
( (
if (err = __is_not_valid_for_motion(), exit(err)); if (err = _is_not_valid_for_motion(), exit(err));
positions = map(global_points, _:0); positions = map(global_points, _:0);
modes = map(global_points, _:(-1)); modes = map(global_points, _:(-1));
durations = map(global_points, global_points:(_i+1):1 - _:1 ); durations = map(global_points, global_points:(_i+1):1 - _:1 );
durations:(-1) = round(60*last_section_delay); durations:(-1) = round(60*last_section_delay);
loop(times, loop(times,
loop( length(positions), loop( length(positions),
__add_path_segment(copy(positions:_), durations:_, modes:_, true) _add_path_segment(copy(positions:_), durations:_, modes:_, true)
) )
); );
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
//stretches or shrinks current path to X percent of what it was before //stretches or shrinks current path to X percent of what it was before
stretch(percentage) -> stretch(percentage) ->
( (
if (err = __is_not_valid_for_motion(), exit(err)); if (err = _is_not_valid_for_motion(), exit(err));
ratio = percentage/100; ratio = percentage/100;
previous_path_length = global_points:(-1):1; previous_path_length = global_points:(-1):1;
for(global_points, _:1 = _:1*ratio ); for(global_points, _:1 = _:1*ratio );
__update(); _update();
print(str('path %s from %.2f to %.2f seconds', print(str('path %s from %.2f to %.2f seconds',
if(ratio<1,'shortened','extended'), if(ratio<1,'shortened','extended'),
previous_path_length/60, previous_path_length/60,
@@ -268,21 +261,20 @@ stretch(percentage) ->
// moves current selected point to player location // moves current selected point to player location
move() -> move() ->
( (
__assert_point_selected(_(p) -> p != null); _assert_point_selected(_(p) -> p != null);
new_position = __camera_position(); new_position = _camera_position();
new_position:(-2) = __adjusted_rot( new_position:(-2) = __adjusted_rot(
global_points:global_selected_point:0:(-2), global_points:global_selected_point:0:(-2),
new_position:(-2) new_position:(-2)
); );
global_points:global_selected_point:0 = new_position; global_points:global_selected_point:0 = new_position;
__update(); _update();
null;
); );
// chenges duration of the current selected segment to X seconds // chenges duration of the current selected segment to X seconds
duration(amount) -> duration(amount) ->
( (
__assert_point_selected(_(p) -> p); // skips nulls and 0 - starting point _assert_point_selected(_(p) -> p); // skips nulls and 0 - starting point
duration = number(amount); duration = number(amount);
new_ticks = round(duration * 60); new_ticks = round(duration * 60);
if (new_ticks < 10, return()); if (new_ticks < 10, return());
@@ -292,63 +284,63 @@ duration(amount) ->
for (range(global_selected_point, length(global_points)), for (range(global_selected_point, length(global_points)),
global_points:_:1 += delta; global_points:_:1 += delta;
); );
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// deletes current keypoint without changing the path length // deletes current keypoint without changing the path length
delete_point() -> delete_point() ->
( (
__assert_point_selected(_(p) -> p != null); _assert_point_selected(_(p) -> p != null);
if (length(global_points) < 2, clear(); return()); if (length(global_points) < 2, clear(); return());
if (global_selected_point == 0, global_points:1:1 = 0); if (global_selected_point == 0, global_points:1:1 = 0);
global_points = filter(global_points, _i != global_selected_point); global_points = filter(global_points, _i != global_selected_point);
if (global_selected_point >= length(global_points), global_selected_point = null); if (global_selected_point >= length(global_points), global_selected_point = null);
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// splits current selected segment in half by adding a keypoint in between // splits current selected segment in half by adding a keypoint in between
split_point() -> split_point() ->
( (
__assert_point_selected(_(p) -> p); // skips nulls and 0 - starting point _assert_point_selected(_(p) -> p); // skips nulls and 0 - starting point
current_time = global_points:global_selected_point:1; current_time = global_points:global_selected_point:1;
previous_time = global_points:(global_selected_point-1):1; previous_time = global_points:(global_selected_point-1):1;
segment_duration = current_time-previous_time; segment_duration = current_time-previous_time;
put( put(
global_points, global_points,
global_selected_point, global_selected_point,
l( [
__get_path_at(global_selected_point-1, previous_time, segment_duration/2), _get_path_at(global_selected_point-1, previous_time, segment_duration/2),
previous_time+segment_duration/2, previous_time+segment_duration/2,
global_points:global_selected_point:2 global_points:global_selected_point:2
), ],
'insert' 'insert'
); );
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// removes all points in the path from the current point // removes all points in the path from the current point
trim_path() -> trim_path() ->
( (
__assert_point_selected(_(p) -> p != null); _assert_point_selected(_(p) -> p != null);
global_points = slice(global_points, 0, global_selected_point); global_points = slice(global_points, 0, global_selected_point);
global_selected_point = null; global_selected_point = null;
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// moves entire camera path keeping the angles to player position being in the starting point // moves entire camera path keeping the angles to player position being in the starting point
transpose() -> transpose() ->
( (
__assert_can_modify_path(); _assert_can_modify_path();
shift = pos(__get_player())-slice(global_points:0:0, 0, 3); shift = pos(_get_player())-slice(global_points:0:0, 0, 3);
shift += 0; shift += 0; shift += 0; shift += 0;
shift = shift + global_player_eye_offset; shift = shift + global_player_eye_offset;
for(global_points, _:0 = _:0 + shift); for(global_points, _:0 = _:0 + shift);
__update(); _update();
print(__get_path_size_string()); print(_get_path_size_string());
); );
// selects either a point of certain number (starting from 1), or closest point // selects either a point of certain number (starting from 1), or closest point
@@ -356,11 +348,11 @@ select(num) ->
( (
if (!global_points, return()); if (!global_points, return());
if (!global_showing_path, return()); if (!global_showing_path, return());
p = __get_player(); p = _get_player();
num = (num+1000*(length(global_points)+1)) % (length(global_points)+1); num = (num+1000*(length(global_points)+1)) % (length(global_points)+1);
selected_point = if (num, num-1, selected_point = if (num, num-1,
__closest_point_to_center( _closest_point_to_center(
p~'pos'+l(0,p~'eye_height',0), p~'pos'+[0, p~'eye_height', 0],
map(global_points, slice(_:0, 0, 3)) map(global_points, slice(_:0, 0, 3))
) )
); );
@@ -383,15 +375,15 @@ __on_player_attacks_entity(p, e) ->
); );
// adds new segment to the path // adds new segment to the path
__add_path_segment(vector, duration, mode, append) -> _add_path_segment(vector, duration, mode, append) ->
( (
if ( (l('sharp','smooth') ~ mode) == null, exit('use smooth or sharp point')); if ( (['sharp','smooth'] ~ mode) == null, exit('use smooth or sharp point'));
l(v, segment_time, m) = global_points:(if(append, -1, 0)); [v, segment_time, m] = global_points:(if(append, -1, 0));
vector:(-2) = __adjusted_rot(v:(-2), vector:(-2)); vector:(-2) = __adjusted_rot(v:(-2), vector:(-2));
if (append, if (append,
global_points += l(vector, segment_time+duration, mode); global_points += [vector, segment_time+duration, mode];
, ,
new_points = l(l(vector, 0, mode)); new_points = [[vector, 0, mode]];
for (global_points, for (global_points,
_:1 += duration; _:1 += duration;
new_points += _; new_points += _;
@@ -411,9 +403,9 @@ __adjusted_rot(previous_rot, current_rot) ->
); );
// returns current path size blurb // returns current path size blurb
__get_path_size_string() -> _get_path_size_string() ->
( (
if (!__is_not_valid_for_motion(), if (!_is_not_valid_for_motion(),
str('%d points, %.1f secs', length(global_points), global_points:(-1):1/60); str('%d points, %.1f secs', length(global_points), global_points:(-1):1/60);
, ,
'Path too small to run'; 'Path too small to run';
@@ -421,16 +413,16 @@ __get_path_size_string() ->
); );
// checks if the current path is valid for motion // checks if the current path is valid for motion
__is_not_valid_for_motion() -> _is_not_valid_for_motion() ->
( (
if(!global_points, return('Path not defined yet')); if(!global_points, return('Path not defined yet'));
if(length(global_points)<2, return('Path not complete - add more points')); if(length(global_points)<2, return('Path not complete - add more points'));
if(!global_dimension || __get_player()~'dimension' != global_dimension, return('Wrong dimension')); if(!global_dimension || _get_player()~'dimension' != global_dimension, return('Wrong dimension'));
false false
); );
// grabs position of a player for a given segment, which segment starts at start point, and offset by index points // grabs position of a player for a given segment, which segment starts at start point, and offset by index points
__get_path_at(segment, start, index) -> _get_path_at(segment, start, index) ->
( (
v = global_path_precalculated:(start+index); v = global_path_precalculated:(start+index);
if(v == null, if(v == null,
@@ -441,57 +433,57 @@ __get_path_at(segment, start, index) ->
); );
// squared euclidean distance between two points // squared euclidean distance between two points
__distsq(vec1, vec2) -> reduce(vec1 - vec2, _a + _*_, 0); _distsq(vec1, vec2) -> reduce(vec1 - vec2, _a + _*_, 0);
//finds index of the closest point from a list to the center point //finds index of the closest point from a list to the center point
__closest_point_to_center(center, points) -> _closest_point_to_center(center, points) ->
( (
reduce(points, reduce(points,
d = __distsq(_, center); if( d<dd, dd=d; _i, _a), d = _distsq(_, center); if( d<dd, dd=d; _i, _a),
dd = __distsq(points:0, center); 0 dd = _distsq(points:0, center); 0
); );
); );
// displays path particles and key point markers on its own thread // displays path particles and key point markers on its own thread
show() -> show() ->
( (
__get_path_size_string(); _get_path_size_string();
if (global_showing_path, return ()); if (global_showing_path, return ());
global_showing_path = true; global_showing_path = true;
global_needs_updating= false; global_needs_updating= false;
__create_markers() -> _create_markers() ->
( (
map(global_points || l(), map(global_points || [],
is_selected = global_selected_point != null && _i == global_selected_point; is_selected = global_selected_point != null && _i == global_selected_point;
caption = if (_i == 0, '1: Start', str('%d: %.1fs', _i+1, global_points:_i:1/60); ); caption = if (_i == 0, '1: Start', str('%d: %.1fs', _i+1, global_points:_i:1/60); );
if (is_selected && _i > 0, if (is_selected && _i > 0,
caption += str(' (%.1fs current segment)', (global_points:_i:1 - global_points:(_i-1):1)/60); caption += str(' (%.1fs current segment)', (global_points:_i:1 - global_points:(_i-1):1)/60);
); );
m = create_marker(caption, _:0, 'observer'); marker = create_marker(caption, _:0, 'observer');
if (is_selected, if (is_selected,
modify(m,'effect','glowing',72000, 0, false, false); modify(marker,'effect','glowing',72000, 0, false, false);
); );
m marker
); );
); );
__show_path_tick() -> __show_path_tick() ->
( (
if (__is_not_valid_for_motion(), return()); if (_is_not_valid_for_motion(), return());
__prepare_path_if_needed(); _prepare_path_if_needed();
loop(global_particle_density, loop(global_particle_density,
segment = floor(rand(length(global_points)-1)); segment = floor(rand(length(global_points)-1));
particle_type = if ((segment+1) == global_selected_point, global_color_a, global_color_b); //'dust 0.1 0.9 0.1 1', 'dust 0.6 0.6 0.6 1'); particle_type = if ((segment+1) == global_selected_point, global_color_a, global_color_b); //'dust 0.1 0.9 0.1 1', 'dust 0.6 0.6 0.6 1');
start = global_points:segment:1; start = global_points:segment:1;
end = global_points:(segment+1):1; end = global_points:(segment+1):1;
index = floor(rand(end-start)); index = floor(rand(end-start));
l(x, y, z) = slice(__get_path_at(segment, start, index), 0, 3); [x, y, z] = slice(_get_path_at(segment, start, index), 0, 3);
particle(particle_type, x, y, z, 1, 0, 0) particle(particle_type, x, y, z, 1, 0, 0)
); );
null null
); );
task( _() -> ( task( _() -> (
global_markers = __create_markers(); global_markers = _create_markers();
on_close = ( _() -> ( on_close = ( _() -> (
for(global_markers, modify(_,'remove')); for(global_markers, modify(_,'remove'));
global_markers = null; global_markers = null;
@@ -500,11 +492,11 @@ show() ->
loop(7200, loop(7200,
if(!global_showing_path, break()); if(!global_showing_path, break());
__get_player(); _get_player();
if (global_needs_updating, if (global_needs_updating,
global_needs_updating = false; global_needs_updating = false;
for(global_markers, modify(_,'remove')); for(global_markers, modify(_,'remove'));
global_markers = __create_markers(); global_markers = _create_markers();
); );
__show_path_tick(); __show_path_tick();
sleep(100, call(on_close)); sleep(100, call(on_close));
@@ -530,9 +522,9 @@ prefer_synced_play() -> (global_prefer_sync = true; 'Synchronized path play');
play() -> play() ->
( (
if (err = __is_not_valid_for_motion(), exit(err)); if (err = _is_not_valid_for_motion(), exit(err));
__prepare_path_if_needed(); _prepare_path_if_needed();
if (!__get_player() || __get_player()~'dimension' != global_dimension, exit('No player in dimension')); if (!_get_player() || _get_player()~'dimension' != global_dimension, exit('No player in dimension'));
task( _() -> ( task( _() -> (
if (global_playing_path, // we don't want to join_task not to lock it just in case. No need to panic here if (global_playing_path, // we don't want to join_task not to lock it just in case. No need to panic here
global_playing_path = false; // cancel current path rendering global_playing_path = false; // cancel current path rendering
@@ -541,14 +533,14 @@ play() ->
showing_path = global_showing_path; showing_path = global_showing_path;
hide(); hide();
sleep(1000); sleep(1000);
sound('ui.button.click', pos(__get_player()), 8, 1); // to synchro with other clips sound('ui.button.click', pos(_get_player()), 8, 1); // to synchro with other clips
sleep(1000); // so particles can discipate sleep(1000); // so particles can discipate
global_playing_path = true; global_playing_path = true;
mspt = 1000 / 60; mspt = 1000 / 60;
start_time = time(); start_time = time();
very_start = start_time; very_start = start_time;
point = 0; point = 0;
p = __get_player(); p = _get_player();
try ( try (
loop( length(global_points)-1, segment = _; loop( length(global_points)-1, segment = _;
start = global_points:segment:1; start = global_points:segment:1;
@@ -556,7 +548,7 @@ play() ->
loop(end-start, loop(end-start,
if (p~'sneaking', global_playing_path = false); if (p~'sneaking', global_playing_path = false);
if (!global_playing_path, throw()); if (!global_playing_path, throw());
v = __get_path_at(segment, start, _)-global_player_eye_offset; v = _get_path_at(segment, start, _)-global_player_eye_offset;
modify(p, 'location', v); modify(p, 'location', v);
point += 1; point += 1;
end_time = time(); end_time = time();
@@ -582,21 +574,21 @@ play() ->
// moves player to a selected camera position // moves player to a selected camera position
place_player() -> place_player() ->
( (
__assert_point_selected(_(p) -> p != null); _assert_point_selected(_(p) -> p != null);
modify(__get_player(), 'location', global_points:global_selected_point:0 - global_player_eye_offset); modify(_get_player(), 'location', global_points:global_selected_point:0 - global_player_eye_offset);
); );
// prepares empty path to fit new points // prepares empty path to fit new points
__prepare_path_if_needed_generic() -> _prepare_path_if_needed_generic() ->
( (
if(!global_path_precalculated, global_path_precalculated = map(range(global_points:(-1):1), null)) if(!global_path_precalculated, global_path_precalculated = map(range(global_points:(-1):1), null))
); );
// linear interpolator // linear interpolator
__interpolator_linear(segment, point) -> _interpolator_linear(segment, point) ->
( (
l(va, start, mode_a) = global_points:segment; [va, start, mode_a] = global_points:segment;
l(vb, end, mode_b) = global_points:(segment+1); [vb, end, mode_b] = global_points:(segment+1);
section = end-start; section = end-start;
dt = point/section; dt = point/section;
dt*vb+(1-dt)*va dt*vb+(1-dt)*va
@@ -605,49 +597,49 @@ __interpolator_linear(segment, point) ->
// normal distribution should look like that // normal distribution should look like that
//(1/sqrt(2*pi*d*d))*euler^(-((x-miu)^2)/(2*d*d)) //(1/sqrt(2*pi*d*d))*euler^(-((x-miu)^2)/(2*d*d))
// but we will be normalizing anyways, so who cares // but we will be normalizing anyways, so who cares
__norm_prob(x, miu, d) -> euler^(-((x-miu)^2)/(2*d*d)); _norm_prob(x, miu, d) -> euler^(-((x-miu)^2)/(2*d*d));
//gauB interpolator //gauB interpolator
__interpolator_gauB(from_index, point, deviation) -> _interpolator_gauB(from_index, point, deviation) ->
( (
components = l(); components = [];
path_point = global_points:from_index:1; path_point = global_points:from_index:1;
try( try(
for(range(from_index+1, length(global_points)), for(range(from_index+1, length(global_points)),
l(v,ptime,mode) = global_points:_; [v,ptime,mode] = global_points:_;
dev = if (deviation > 0, deviation, dev = if (deviation > 0, deviation,
devs = l(); devs = [];
if (_+1 < length(global_points), devs += global_points:(_+1):1-ptime); if (_+1 < length(global_points), devs += global_points:(_+1):1-ptime);
if (_-1 >= 0, devs += ptime-global_points:(_-1):1); if (_-1 >= 0, devs += ptime-global_points:(_-1):1);
0.6*reduce(devs, _a+_, 0)/length(devs) 0.6*reduce(devs, _a+_, 0)/length(devs)
); );
impact = __norm_prob(path_point+point, ptime, dev); impact = _norm_prob(path_point+point, ptime, dev);
//if(rtotal && impact < 0.000001*rtotal, throw()); // can work badly on segments with vastly diff lengths //if(rtotal && impact < 0.000001*rtotal, throw()); // can work badly on segments with vastly diff lengths
components += l(v, impact); components += [v, impact];
rtotal += impact rtotal += impact
) )
); );
try( try(
for(range(from_index, -1, -1), for(range(from_index, -1, -1),
l(v,ptime,mode) = global_points:_; [v,ptime,mode] = global_points:_;
dev = if (deviation > 0, deviation, dev = if (deviation > 0, deviation,
devs = l(); devs = [];
if (_+1 < length(global_points), devs += global_points:(_+1):1-ptime); if (_+1 < length(global_points), devs += global_points:(_+1):1-ptime);
if (_-1 >= 0, devs += ptime-global_points:(_-1):1); if (_-1 >= 0, devs += ptime-global_points:(_-1):1);
0.6*reduce(devs, _a+_, 0)/length(devs) 0.6*reduce(devs, _a+_, 0)/length(devs)
); );
impact = __norm_prob(path_point+point, ptime, dev); impact = _norm_prob(path_point+point, ptime, dev);
//if(ltotal && impact < 0.000001*ltotal, throw()); //if(ltotal && impact < 0.000001*ltotal, throw());
components += l(v, impact); components += [v, impact];
ltotal += impact ltotal += impact
) )
); );
total = rtotal+ltotal; total = rtotal+ltotal;
reduce(components, _a+_:0*(_:1/total), l(0,0,0,0,0)) reduce(components, _a+_:0*(_:1/total), [0,0,0,0,0])
); );
// Catmull-Rom spline // Catmull-Rom spline
__interpolator_cr(from_index, point) -> _interpolator_cr(from_index, point) ->
( (
total = global_points:(from_index+1):1 - global_points:from_index:1; total = global_points:(from_index+1):1 - global_points:from_index:1;
p__1 = global_points:(if(from_index == 0, 0, from_index-1)):0; p__1 = global_points:(if(from_index == 0, 0, from_index-1)):0;
@@ -680,11 +672,11 @@ load(file) ->
( (
path_nbt = read_file(file, 'nbt'); path_nbt = read_file(file, 'nbt');
if (!path_nbt, exit('No path to load: '+file)); if (!path_nbt, exit('No path to load: '+file));
new_points = map(get(path_nbt, 'points[]'), l(_:'pos[]', _:'duration', _:'type')); new_points = map(get(path_nbt, 'points[]'), [_:'pos[]', _:'duration', _:'type']);
if (!new_points || first(new_points, length(_:0) != 5), if (!new_points || first(new_points, length(_:0) != 5),
exit('Incorrect data for :'+file); exit('Incorrect data for :'+file);
); );
__start_with(_(outer(new_points)) -> new_points); _start_with(_(outer(new_points)) -> new_points);
print('loaded '+file); print('loaded '+file);
); );