@@ -7,8 +7,6 @@ model_part_stand:
77 marker : true
88 gravity : false
99 visible : false
10- custom_name_visible : true
11- custom_name : part
1210
1311spawn_model :
1412 type : task
@@ -23,13 +21,161 @@ spawn_model:
2321 - stop
2422 - ~yaml id:<[yamlid] > load:<[filename] >
2523 - define parts <yaml[<[yamlid] > ] .read[models] >
24+ - flag server dmodels_data.model_<[model_name] > :<[parts] >
25+ - flag server dmodels_data.animations_<[model_name] > :<yaml[<[yamlid] > ] .read[animations] ||<map> >
2626 - yaml unload id:<[yamlid] >
27+ - spawn model_part_stand <[location] > save:root
28+ - flag <entry[root] .spawned_entity> dmodel_model_id:<[model_name] >
2729 - foreach <[parts] > key:id as:part:
2830 - if <[part.empty] ||false> :
2931 - foreach next
3032 - define rots <[part.rotation] .split[,] .parse[to_radians] >
3133 # Idk wtf is with the scale here. It's somewhere in the range of 25 to 26. 25.45 seems closest in one of my tests,
32- # but I think that's minecraft packet location imprecision at fault so it's probably just 26.
33- - define offset <location[<[part.origin] > ] .div[26] .rotate_around_y[<util.pi> ] >
34- - define pose [head=<[rots] .get[1] .mul[-1] > ,<[rots] .get[2] .mul[-1] > ,<[rots] .get[3] > ]
35- - spawn model_part_stand[equipment=[helmet=<[part.item] > ] ;armor_pose=<[pose] > ] <[location] .add[<[offset] > ] > save:spawned
34+ # but I think that's minecraft packet location imprecision at fault so it's possibly just 26?
35+ # Supposedly it's 25.6 according to external docs (16 * 1.6), but that also is wrong in my testing.
36+ - define offset <location[<[part.origin] > ] .div[25.6] .rotate_around_y[<util.pi> ] >
37+ - define pose <[rots] .get[1] .mul[-1] > ,<[rots] .get[2] .mul[-1] > ,<[rots] .get[3] >
38+ - spawn model_part_stand[equipment=[helmet=<[part.item] > ] ;armor_pose=[head=<[pose] > ]] <[location] .add[<[offset] > ] > save:spawned
39+ - flag <entry[spawned] .spawned_entity> dmodel_def_pose:<[pose] >
40+ - flag <entry[spawned] .spawned_entity> dmodel_def_offset:<[offset] >
41+ - flag <entry[spawned] .spawned_entity> dmodel_root:<entry[root] .spawned_entity>
42+ - flag <entry[root] .spawned_entity> dmodel_parts:->:<entry[spawned] .spawned_entity>
43+ - flag <entry[root] .spawned_entity> dmodel_anim_part.<[id] > :->:<entry[spawned] .spawned_entity>
44+ - foreach <[parts] > key:id as:part:
45+ - foreach <[part.pairs] > as:pair_id:
46+ - flag <entry[root] .spawned_entity> dmodel_anim_part.<[id] > :|:<entry[root] .spawned_entity.flag[dmodel_anim_part.<[pair_id] > ] ||<list> >
47+ - determine <entry[root] .spawned_entity>
48+
49+ dmodels_correct_to_default_position :
50+ type : task
51+ debug : false
52+ definitions : root_entity
53+ script :
54+ - foreach <[root_entity] .flag[dmodel_parts] > as:part:
55+ - adjust <[part] > armor_pose:[head=<[part] .flag[dmodel_def_pose] > ]
56+ - teleport <[part] > <[root_entity] .location.add[<[part] .flag[dmodel_def_offset] > ] >
57+
58+ dmodels_animate :
59+ type : task
60+ debug : false
61+ definitions : root_entity|animation
62+ script :
63+ - run dmodels_correct_to_default_position def.root_entity:<[root_entity] >
64+ - define animation_data <server.flag[dmodels_data.animations_<[root_entity] .flag[dmodel_model_id] > .<[animation] > ] ||null>
65+ - if <[animation_data] > == null:
66+ - debug error "[DModels] Cannot animate entity <[root_entity] .uuid> due to model <[root_entity] .flag[dmodel_model_id] > not having an animation named <[animation] > "
67+ - stop
68+ - flag <[root_entity] > dmodels_animation_id:<[animation] >
69+ - flag <[root_entity] > dmodels_anim_time:0
70+ - flag server dmodels_anim_active.<[root_entity] .uuid>
71+
72+ dmodels_move_to_frame :
73+ type : task
74+ debug : false
75+ definitions : root_entity|animation|timespot
76+ script :
77+ - define animation_data <server.flag[dmodels_data.animations_<[root_entity] .flag[dmodel_model_id] > .<[animation] > ] ||null>
78+ - if <[timespot] > > <[animation_data.length] > :
79+ - choose <[animation_data.loop] > :
80+ - case loop:
81+ - define timespot <[timespot] .mod[<[animation_data.length] > ] >
82+ - case once:
83+ - flag server dmodels_anim_active.<[root_entity] .uuid> :!
84+ - if <[root_entity] .has_flag[dmodels_default_animation] > :
85+ - run dmodels_animate def.root_entity:<[root_entity] > def.animation:<[root_entity] .flag[dmodels_default_animation] >
86+ - else :
87+ - run dmodels_correct_to_default_position def.root_entity:<[root_entity] >
88+ - stop
89+ - case hold:
90+ - define timespot <[animation_data.length] >
91+ - flag server dmodels_anim_active.<[root_entity] .uuid> :!
92+ - foreach <[animation_data.animators] > key:part_id as:animator:
93+ - define ents <[root_entity] .flag[dmodel_anim_part.<[part_id] > ] ||<list> >
94+ - if <[ents] .is_empty> :
95+ - foreach next
96+ - foreach position|rotation as:channel:
97+ - define relevant_frames <[animator.frames] .filter[get[channel] .equals[<[channel] > ] ] >
98+ - define before_frame <[relevant_frames] .filter[get[time] .is_less_than_or_equal_to[<[timespot] > ] ] .last||null>
99+ - define after_frame <[relevant_frames] .filter[get[time] .is_more_than_or_equal_to[<[timespot] > ] ] .first||null>
100+ - if <[before_frame] > == null:
101+ - define before_frame <[after_frame] >
102+ - if <[after_frame] > == null:
103+ - define after_frame <[before_frame] >
104+ - if <[before_frame] > == null:
105+ - foreach next
106+ - define time_range <[after_frame.time] .sub[<[before_frame.time] > ] >
107+ - if <[time_range] > == 0:
108+ - define time_percent 0
109+ - else :
110+ - define time_percent <[timespot] .sub[<[before_frame.time] > ] .div[<[time_range] > ] >
111+ - choose <[before_frame.interpolation] > :
112+ - case catmullrom:
113+ - define before_extra <[relevant_frames] .filter[get[time] .is_less_than[<[before_frame.time] > ] ] .last||null>
114+ - if <[before_extra] > == null:
115+ - define before_extra <[before_frame] >
116+ - define after_extra <[relevant_frames] .filter[get[time] .is_more_than[<[after_frame.time] > ] ] .first||null>
117+ - if <[after_extra] > == null:
118+ - define after_extra <[after_frame] >
119+ - define p0 <[before_extra.data] .as_location>
120+ - define p1 <[before_frame.data] .as_location>
121+ - define p2 <[after_frame.data] .as_location>
122+ - define p3 <[after_extra.data] .as_location>
123+ - define data <proc[dmodels_catmullrom_proc] .context[<[p0] > |<[p1] > |<[p2] > |<[p3] > |<[time_percent] > ] >
124+ - case linear:
125+ - define data <[after_frame.data] .as_location.sub[<[before_frame.data] > ] .mul[<[time_percent] > ] .add[<[before_frame.data] > ] .xyz>
126+ - case step:
127+ - define data <[before_frame.data] >
128+ - foreach <[ents] > as:ent:
129+ - choose <[channel] > :
130+ - case position:
131+ - teleport <[ent] > <[root_entity] .location.add[<[ent] .flag[dmodel_def_offset] .add[<[data] .as_location.div[25.6] > ] > ] >
132+ - case rotation:
133+ - define radian_rot <[data] .as_location.xyz.split[,] .parse[to_radians] .separated_by[,] >
134+ - adjust <[ent] > armor_pose:[head=<[ent] .flag[dmodel_def_pose] .as_location.add[<[radian_rot] > ] .xyz> ]
135+
136+ dmodels_catmullrom_get_t :
137+ type : procedure
138+ debug : false
139+ definitions : t|p0|p1
140+ script :
141+ # This is more complex for different alpha values, but alpha=1 compresses down to a '.length' call conveniently
142+ - determine <[p1] .sub[<[p0] > ] .length.add[<[t] > ] >
143+
144+ dmodels_catmullrom_proc :
145+ type : procedure
146+ debug : false
147+ definitions : p0|p1|p2|p3|t
148+ script :
149+ # TODO: Validate this mess
150+ - define t0 0
151+ - define t1 <proc[dmodels_catmullrom_get_t] .context[0|<[p0] > |<[p1] > ] >
152+ - define t2 <proc[dmodels_catmullrom_get_t] .context[<[t1] > |<[p1] > |<[p2] > ] >
153+ - define t3 <proc[dmodels_catmullrom_get_t] .context[<[t2] > |<[p2] > |<[p3] > ] >
154+ - define t <[t2] .sub[<[t1] > ] .mul[<[t] > ] .add[<[t1] > ] >
155+ # ( t1-t )/( t1-t0 )*p0 + ( t-t0 )/( t1-t0 )*p1;
156+ - define a1 <[p0] .mul[<[t1] .sub[<[t] > ] .div[<[t1] > ] > ] .add[<[p1] .mul[<[t] .div[<[t1] > ] > ] > ] >
157+ # ( t2-t )/( t2-t1 )*p1 + ( t-t1 )/( t2-t1 )*p2;
158+ - define a2 <[p1] .mul[<[t2] .sub[<[t] > ] .div[<[t2] .sub[<[t1] > ] > ] > ] .add[<[p2] .mul[<[t] .sub[<[t1] > ] .div[<[t2] .sub[<[t1] > ] > ] > ] > ] >
159+ # FVector A3 = ( t3-t )/( t3-t2 )*p2 + ( t-t2 )/( t3-t2 )*p3;
160+ - define a3 <[a1] .mul[<[t2] .sub[<[t] > ] .div[<[t2] > ] > ] .add[<[a2] .mul[<[t] .div[<[t2] > ] > ] > ] >
161+ # FVector B1 = ( t2-t )/( t2-t0 )*A1 + ( t-t0 )/( t2-t0 )*A2;
162+ - define b1 <[a1] .mul[<[t2] .sub[<[t] > ] .div[<[t2] > ] > ] .add[<[a2] .mul[<[t] .div[<[t2] > ] > ] > ] >
163+ # FVector B2 = ( t3-t )/( t3-t1 )*A2 + ( t-t1 )/( t3-t1 )*A3;
164+ - define b2 <[a2] .mul[<[t3] .sub[<[t] > ] .div[<[t3] .sub[<[t1] > ] > ] > ] .add[<[a3] .mul[<[t] .sub[<[t1] > ] .div[<[t3] .sub[<[t1] > ] > ] > ] > ] >
165+ # FVector C = ( t2-t )/( t2-t1 )*B1 + ( t-t1 )/( t2-t1 )*B2;
166+ - determine <[b1] .mul[<[t2] .sub[<[t] > ] .div[<[t2] .sub[<[t1] > ] > ] > ] .add[<[b2] .mul[<[t] .sub[<[t1] > ] .div[<[t2] .sub[<[t1] > ] > ] > ] > ] >
167+
168+ dmodels_animator :
169+ type : world
170+ debug : false
171+ events :
172+ on server start priority:-1000 :
173+ # Cleanup
174+ - flag server dmodels_data:!
175+ - flag server dmodels_anim_active:!
176+ on tick server_flagged:dmodels_anim_active :
177+ - foreach <server.flag[dmodels_anim_active] > key:root_id:
178+ - define root <entity[<[root_id] > ] ||null>
179+ - if <[root] .is_spawned||false> :
180+ - 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] >
181+ - flag <[root] > dmodels_anim_time:++
0 commit comments