|
| 1 | +########################### |
| 2 | +# This file is part of dModels / Denizen Models. |
| 3 | +# Refer to the header of "dmodels_main.dsc" for more information. |
| 4 | +########################### |
| 5 | + |
| 6 | + |
| 7 | +dmodels_end_animation: |
| 8 | + type: task |
| 9 | + debug: false |
| 10 | + definitions: root_entity |
| 11 | + script: |
| 12 | + - flag <[root_entity]> dmodels_animation_id:! |
| 13 | + - flag <[root_entity]> dmodels_anim_time:0 |
| 14 | + - flag server dmodels_anim_active.<[root_entity].uuid>:! |
| 15 | + - run dmodels_reset_model_position def.root_entity:<[root_entity]> |
| 16 | + |
| 17 | +dmodels_animate: |
| 18 | + type: task |
| 19 | + debug: false |
| 20 | + definitions: root_entity|animation |
| 21 | + script: |
| 22 | + - run dmodels_reset_model_position def.root_entity:<[root_entity]> |
| 23 | + - define animation_data <server.flag[dmodels_data.animations_<[root_entity].flag[dmodel_model_id]>.<[animation]>]||null> |
| 24 | + - if <[animation_data]> == null: |
| 25 | + - debug error "[DModels] Cannot animate entity <[root_entity].uuid> due to model <[root_entity].flag[dmodel_model_id]> not having an animation named <[animation]>" |
| 26 | + - stop |
| 27 | + - flag <[root_entity]> dmodels_animation_id:<[animation]> |
| 28 | + - flag <[root_entity]> dmodels_anim_time:0 |
| 29 | + - flag server dmodels_anim_active.<[root_entity].uuid>:<[root_entity]> |
| 30 | + |
| 31 | +dmodels_move_to_frame: |
| 32 | + type: task |
| 33 | + debug: false |
| 34 | + definitions: root_entity|animation|timespot|delay_pose |
| 35 | + script: |
| 36 | + - define model_data <server.flag[dmodels_data.model_<[root_entity].flag[dmodel_model_id]>]> |
| 37 | + - define animation_data <server.flag[dmodels_data.animations_<[root_entity].flag[dmodel_model_id]>.<[animation]>]> |
| 38 | + - if <[timespot]> > <[animation_data.length]>: |
| 39 | + - choose <[animation_data.loop]>: |
| 40 | + - case loop: |
| 41 | + - define timespot <[timespot].mod[<[animation_data.length]>]> |
| 42 | + - case once: |
| 43 | + - flag server dmodels_anim_active.<[root_entity].uuid>:! |
| 44 | + - if <[root_entity].has_flag[dmodels_default_animation]>: |
| 45 | + - run dmodels_animate def.root_entity:<[root_entity]> def.animation:<[root_entity].flag[dmodels_default_animation]> |
| 46 | + - else: |
| 47 | + - run dmodels_reset_model_position def.root_entity:<[root_entity]> |
| 48 | + - stop |
| 49 | + - case hold: |
| 50 | + - define timespot <[animation_data.length]> |
| 51 | + - flag server dmodels_anim_active.<[root_entity].uuid>:! |
| 52 | + - define center <[root_entity].location.with_pitch[0].below[0.72]> |
| 53 | + - define yaw_mod <[root_entity].location.yaw.add[180].to_radians> |
| 54 | + - define parentage <map> |
| 55 | + - foreach <[animation_data.animators]> key:part_id as:animator: |
| 56 | + - define framedata.position 0,0,0 |
| 57 | + - define framedata.rotation 0,0,0 |
| 58 | + - foreach position|rotation as:channel: |
| 59 | + - define relevant_frames <[animator.frames].filter[get[channel].equals[<[channel]>]]> |
| 60 | + - define before_frame <[relevant_frames].filter[get[time].is_less_than_or_equal_to[<[timespot]>]].last||null> |
| 61 | + - define after_frame <[relevant_frames].filter[get[time].is_more_than_or_equal_to[<[timespot]>]].first||null> |
| 62 | + - if <[before_frame]> == null: |
| 63 | + - define before_frame <[after_frame]> |
| 64 | + - if <[after_frame]> == null: |
| 65 | + - define after_frame <[before_frame]> |
| 66 | + - if <[before_frame]> == null: |
| 67 | + - define data 0,0,0 |
| 68 | + - else: |
| 69 | + - define time_range <[after_frame.time].sub[<[before_frame.time]>]> |
| 70 | + - if <[time_range]> == 0: |
| 71 | + - define time_percent 0 |
| 72 | + - else: |
| 73 | + - define time_percent <[timespot].sub[<[before_frame.time]>].div[<[time_range]>]> |
| 74 | + - choose <[before_frame.interpolation]>: |
| 75 | + - case catmullrom: |
| 76 | + - define before_extra <[relevant_frames].filter[get[time].is_less_than[<[before_frame.time]>]].last||null> |
| 77 | + - if <[before_extra]> == null: |
| 78 | + - define before_extra <[animation_data.loop].equals[loop].if_true[<[relevant_frames].last>].if_false[<[before_frame]>]> |
| 79 | + - define after_extra <[relevant_frames].filter[get[time].is_more_than[<[after_frame.time]>]].first||null> |
| 80 | + - if <[after_extra]> == null: |
| 81 | + - define after_extra <[animation_data.loop].equals[loop].if_true[<[relevant_frames].first>].if_false[<[after_frame]>]> |
| 82 | + - define p0 <[before_extra.data].as_location> |
| 83 | + - define p1 <[before_frame.data].as_location> |
| 84 | + - define p2 <[after_frame.data].as_location> |
| 85 | + - define p3 <[after_extra.data].as_location> |
| 86 | + - define data <proc[dmodels_catmullrom_proc].context[<[p0]>|<[p1]>|<[p2]>|<[p3]>|<[time_percent]>]> |
| 87 | + - case linear: |
| 88 | + - define data <[after_frame.data].as_location.sub[<[before_frame.data]>].mul[<[time_percent]>].add[<[before_frame.data]>].xyz> |
| 89 | + - case step: |
| 90 | + - define data <[before_frame.data]> |
| 91 | + - define framedata.<[channel]> <[data]> |
| 92 | + - define this_part <[model_data.<[part_id]>]> |
| 93 | + - define this_rots <[this_part.rotation].split[,].parse[to_radians]> |
| 94 | + - define pose <[this_rots].get[1].mul[-1]>,<[this_rots].get[2].mul[-1]>,<[this_rots].get[3]> |
| 95 | + - define parent_id <[this_part.parent]> |
| 96 | + - define parent_pos <location[<[parentage.<[parent_id]>.position]||0,0,0>]> |
| 97 | + - define parent_rot <location[<[parentage.<[parent_id]>.rotation]||0,0,0>]> |
| 98 | + - define parent_offset <location[<[parentage.<[parent_id]>.offset]||0,0,0>]> |
| 99 | + - define parent_raw_offset <[model_data.<[parent_id]>.origin]||0,0,0> |
| 100 | + - define rel_offset <location[<[this_part.origin]>].sub[<[parent_raw_offset]>]> |
| 101 | + - define rot_offset <[rel_offset].proc[dmodels_rot_proc].context[<[parent_rot]>]> |
| 102 | + - define new_pos <[framedata.position].as_location.proc[dmodels_rot_proc].context[<[parent_rot]>].add[<[rot_offset]>].add[<[parent_pos]>]> |
| 103 | + - define new_rot <[framedata.rotation].as_location.add[<[parent_rot]>].add[<[pose]>]> |
| 104 | + - define parentage.<[part_id]>.position <[new_pos]> |
| 105 | + - define parentage.<[part_id]>.rotation <[new_rot]> |
| 106 | + - define parentage.<[part_id]>.offset <[rot_offset].add[<[parent_offset]>]> |
| 107 | + - foreach <[root_entity].flag[dmodel_anim_part.<[part_id]>]||<list>> as:ent: |
| 108 | + - teleport <[ent]> <[center].add[<[new_pos].div[16].rotate_around_y[<[yaw_mod].mul[-1]>]>]> |
| 109 | + - adjust <[ent]> reset_client_location |
| 110 | + - define radian_rot <[new_rot].xyz.split[,]> |
| 111 | + - define pose <[radian_rot].get[1]>,<[radian_rot].get[2]>,<[radian_rot].get[3]> |
| 112 | + - if <[delay_pose]>: |
| 113 | + - adjust <[ent]> armor_pose:[head=<[ent].flag[dmodels_next_pose].if_null[<[ent].flag[dmodel_def_pose]>]>] |
| 114 | + - flag <[ent]> dmodels_next_pose:<[pose]> |
| 115 | + - else: |
| 116 | + - adjust <[ent]> armor_pose:[head=<[pose]>] |
| 117 | + - adjust <[ent]> send_update_packets |
| 118 | + |
| 119 | +dmodels_rot_proc: |
| 120 | + type: procedure |
| 121 | + debug: false |
| 122 | + definitions: loc|rot |
| 123 | + script: |
| 124 | + - determine <[loc].rotate_around_x[<[rot].x.mul[-1]>].rotate_around_y[<[rot].y.mul[-1]>].rotate_around_z[<[rot].z>]> |
| 125 | + |
| 126 | +dmodels_catmullrom_get_t: |
| 127 | + type: procedure |
| 128 | + debug: false |
| 129 | + definitions: t|p0|p1 |
| 130 | + script: |
| 131 | + # This is more complex for different alpha values, but alpha=1 compresses down to a '.vector_length' call conveniently |
| 132 | + - determine <[p1].sub[<[p0]>].vector_length.add[<[t]>]> |
| 133 | + |
| 134 | +dmodels_catmullrom_proc: |
| 135 | + type: procedure |
| 136 | + debug: false |
| 137 | + definitions: p0|p1|p2|p3|t |
| 138 | + script: |
| 139 | + # Zero distances are impossible to calculate |
| 140 | + - if <[p2].sub[<[p1]>].vector_length> < 0.01: |
| 141 | + - determine <[p2]> |
| 142 | + # Based on https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline#Code_example_in_Unreal_C++ |
| 143 | + # With safety checks added for impossible situations |
| 144 | + - define t0 0 |
| 145 | + - define t1 <proc[dmodels_catmullrom_get_t].context[0|<[p0]>|<[p1]>]> |
| 146 | + - define t2 <proc[dmodels_catmullrom_get_t].context[<[t1]>|<[p1]>|<[p2]>]> |
| 147 | + - define t3 <proc[dmodels_catmullrom_get_t].context[<[t2]>|<[p2]>|<[p3]>]> |
| 148 | + # Divide-by-zero safety check |
| 149 | + - if <[t1].abs> < 0.001 || <[t2].sub[<[t1]>].abs> < 0.001 || <[t2].abs> < 0.001 || <[t3].sub[<[t1]>].abs> < 0.001: |
| 150 | + - determine <[p2].sub[<[p1]>].mul[<[t]>].add[<[p1]>]> |
| 151 | + - define t <[t2].sub[<[t1]>].mul[<[t]>].add[<[t1]>]> |
| 152 | + # ( t1-t )/( t1-t0 )*p0 + ( t-t0 )/( t1-t0 )*p1; |
| 153 | + - define a1 <[p0].mul[<[t1].sub[<[t]>].div[<[t1]>]>].add[<[p1].mul[<[t].div[<[t1]>]>]>]> |
| 154 | + # ( t2-t )/( t2-t1 )*p1 + ( t-t1 )/( t2-t1 )*p2; |
| 155 | + - define a2 <[p1].mul[<[t2].sub[<[t]>].div[<[t2].sub[<[t1]>]>]>].add[<[p2].mul[<[t].sub[<[t1]>].div[<[t2].sub[<[t1]>]>]>]>]> |
| 156 | + # FVector A3 = ( t3-t )/( t3-t2 )*p2 + ( t-t2 )/( t3-t2 )*p3; |
| 157 | + - define a3 <[a1].mul[<[t2].sub[<[t]>].div[<[t2]>]>].add[<[a2].mul[<[t].div[<[t2]>]>]>]> |
| 158 | + # FVector B1 = ( t2-t )/( t2-t0 )*A1 + ( t-t0 )/( t2-t0 )*A2; |
| 159 | + - define b1 <[a1].mul[<[t2].sub[<[t]>].div[<[t2]>]>].add[<[a2].mul[<[t].div[<[t2]>]>]>]> |
| 160 | + # FVector B2 = ( t3-t )/( t3-t1 )*A2 + ( t-t1 )/( t3-t1 )*A3; |
| 161 | + - define b2 <[a2].mul[<[t3].sub[<[t]>].div[<[t3].sub[<[t1]>]>]>].add[<[a3].mul[<[t].sub[<[t1]>].div[<[t3].sub[<[t1]>]>]>]>]> |
| 162 | + # FVector C = ( t2-t )/( t2-t1 )*B1 + ( t-t1 )/( t2-t1 )*B2; |
| 163 | + - determine <[b1].mul[<[t2].sub[<[t]>].div[<[t2].sub[<[t1]>]>]>].add[<[b2].mul[<[t].sub[<[t1]>].div[<[t2].sub[<[t1]>]>]>]>]> |
| 164 | + |
| 165 | +dmodels_animator: |
| 166 | + type: world |
| 167 | + debug: false |
| 168 | + events: |
| 169 | + on tick server_flagged:dmodels_anim_active: |
| 170 | + - foreach <server.flag[dmodels_anim_active]> as:root: |
| 171 | + - if <[root].is_spawned||false>: |
| 172 | + - run dmodels_move_to_frame def.root_entity:<[root]> def.animation:<[root].flag[dmodels_animation_id]> def.timespot:<[root].flag[dmodels_anim_time].div[20]> def.delay_pose:true |
| 173 | + - flag <[root]> dmodels_anim_time:++ |
0 commit comments