Skip to content

Commit ab493a8

Browse files
committed
bones logic
1 parent f235c1b commit ab493a8

File tree

4 files changed

+106
-47
lines changed

4 files changed

+106
-47
lines changed

DenizenModelsConverter/BBModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public class Outliner
9393

9494
public List<Guid> Children = new();
9595

96-
public List<Guid> Paired = new();
96+
public Guid? Parent;
9797
}
9898

9999
public class Animation

DenizenModelsConverter/BBModelReader.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,15 @@ public static void AddOutlineChild(BBModel model, BBModel.Outliner outline, JTok
231231
element.Rotation = new DoubleVector();
232232
element.Origin = new DoubleVector();
233233
element.Outline = specialSideOutline;
234+
specialSideOutline.Parent = outline.UUID;
234235
specialSideOutline.Children.Add(element.UUID);
235236
model.Outlines.Add(specialSideOutline);
236-
outline.Paired.Add(specialSideOutline.UUID);
237237
}
238238
}
239239
else
240240
{
241241
BBModel.Outliner subLine = ReadOutliner(model, (JObject)child, names);
242-
outline.Paired.Add(subLine.UUID);
243-
outline.Paired.AddRange(subLine.Paired);
242+
subLine.Parent = outline.UUID;
244243
}
245244
}
246245

DenizenModelsConverter/PackMaker.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public static void BuildPack(string rawModelPath, BBModel model, string item, st
8686
JObject skippedEntry = new();
8787
skippedEntry.Add("name", outline.Name);
8888
skippedEntry.Add("empty", true);
89-
skippedEntry.Add("pairs", new JArray(outline.Paired.Select(p => p.ToString()).ToArray()));
89+
skippedEntry.Add("parent", outline.Parent == null ? "none" : outline.Parent.ToString());
9090
modelSet.Add(outline.UUID.ToString(), skippedEntry);
9191
continue;
9292
}
@@ -110,7 +110,7 @@ public static void BuildPack(string rawModelPath, BBModel model, string item, st
110110
modelEntry.Add("item", $"{item}[custom_model_data={id}]");
111111
modelEntry.Add("origin", outline.Origin.ToDenizenString());
112112
modelEntry.Add("rotation", outline.Rotation.ToDenizenString());
113-
modelEntry.Add("pairs", new JArray(outline.Paired.Select(p => p.ToString()).ToArray()));
113+
modelEntry.Add("parent", outline.Parent == null ? "none" : outline.Parent.ToString());
114114
modelSet.Add(outline.UUID.ToString(), modelEntry);
115115
}
116116
Debug("Models done. Outputting new item override...");
@@ -153,11 +153,42 @@ public static void BuildPack(string rawModelPath, BBModel model, string item, st
153153
animations.Add(animation.Name, jAnimation);
154154
}
155155
Debug("Animations done. Building Denizen file...");
156+
JArray partsOrder = new();
157+
BuildPartsOrder(model, null, partsOrder);
158+
if (partsOrder.Count != model.Outlines.Count)
159+
{
160+
throw new Exception($"Failed to build parts order, listed {partsOrder.Count} but expected {model.Outlines.Count} ... are bone parents wrong?");
161+
}
156162
JObject denizenFile = new();
163+
denizenFile.Add("order", partsOrder);
157164
denizenFile.Add("models", modelSet);
158165
denizenFile.Add("animations", animations);
159166
File.WriteAllText($"{rawModelPath.Replace(".bbmodel", "")}.dmodel.yml", denizenFile.ToString());
160167
Console.WriteLine("Exported full bbmodel.");
161168
}
169+
170+
public static void BuildPartsOrder(BBModel model, Guid? id, JArray output)
171+
{
172+
List<BBModel.Outliner> partsToAdd = new();
173+
foreach (BBModel.Outliner outline in model.Outlines)
174+
{
175+
if (outline.Parent == id)
176+
{
177+
partsToAdd.Add(outline);
178+
}
179+
}
180+
if (partsToAdd.IsEmpty())
181+
{
182+
return;
183+
}
184+
foreach (BBModel.Outliner part in partsToAdd)
185+
{
186+
output.Add(part.UUID.ToString());
187+
}
188+
foreach (BBModel.Outliner part in partsToAdd)
189+
{
190+
BuildPartsOrder(model, part.UUID, output);
191+
}
192+
}
162193
}
163194
}

scripts/dmodels.dsc

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
model_part_stand:
2+
dmodel_part_stand:
33
type: entity
44
debug: false
55
entity_type: armor_stand
@@ -8,25 +8,46 @@ model_part_stand:
88
gravity: false
99
visible: false
1010

11-
spawn_model:
11+
dmodels_load_model:
1212
type: task
1313
debug: false
14-
definitions: model_name|location
14+
definitions: model_name
1515
script:
16-
- define location <[location].center>
1716
- define yamlid dmodels_<[model_name]>
1817
- define filename data/models/<[model_name]>.dmodel.yml
1918
- if !<server.has_file[<[filename]>]>:
2019
- debug error "Invalid model <[model_name]>, file does not exist: <[filename]>, cannot load"
2120
- stop
2221
- ~yaml id:<[yamlid]> load:<[filename]>
22+
- define order <yaml[<[yamlid]>].read[order]>
2323
- 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>>
24+
- define animations <yaml[<[yamlid]>].read[animations]||<map>>
2625
- yaml unload id:<[yamlid]>
27-
- spawn model_part_stand <[location]> save:root
26+
- foreach <[order]> as:id:
27+
- define raw_parts.<[id]> <[parts.<[id]>]>
28+
- foreach <[animations]> key:name as:anim:
29+
- foreach <[order]> as:id:
30+
- if <[anim.animators].contains[<[id]>]>:
31+
- define raw_animators.<[id]> <[anim.animators.<[id]>]>
32+
- else:
33+
- define raw_animators.<[id]> <map[frames=<list>]>
34+
- define anim.animators <[raw_animators]>
35+
- define raw_animations.<[name]> <[anim]>
36+
- flag server dmodels_data.model_<[model_name]>:<[raw_parts]>
37+
- flag server dmodels_data.animations_<[model_name]>:<[raw_animations]>
38+
39+
dmodels_spawn_model:
40+
type: task
41+
debug: false
42+
definitions: model_name|location
43+
script:
44+
- if !<server.has_flag[dmodels_data.model_<[model_name]>]>:
45+
- debug error "[DModels] cannot spawn model <[model_name]>, model not loaded"
46+
- stop
47+
- define location <[location].center>
48+
- spawn dmodel_part_stand <[location]> save:root
2849
- flag <entry[root].spawned_entity> dmodel_model_id:<[model_name]>
29-
- foreach <[parts]> key:id as:part:
50+
- foreach <server.flag[dmodels_data.model_<[model_name]>]> key:id as:part:
3051
- if <[part.empty]||false>:
3152
- foreach next
3253
- define rots <[part.rotation].split[,].parse[to_radians]>
@@ -35,15 +56,12 @@ spawn_model:
3556
# Supposedly it's 25.6 according to external docs (16 * 1.6), but that also is wrong in my testing.
3657
- define offset <location[<[part.origin]>].div[25.6].rotate_around_y[<util.pi>]>
3758
- 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
59+
- spawn dmodel_part_stand[equipment=[helmet=<[part.item]>];armor_pose=[head=<[pose]>]] <[location].add[<[offset]>]> save:spawned
3960
- flag <entry[spawned].spawned_entity> dmodel_def_pose:<[pose]>
4061
- flag <entry[spawned].spawned_entity> dmodel_def_offset:<[offset]>
4162
- flag <entry[spawned].spawned_entity> dmodel_root:<entry[root].spawned_entity>
4263
- flag <entry[root].spawned_entity> dmodel_parts:->:<entry[spawned].spawned_entity>
4364
- 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>>
4765
- determine <entry[root].spawned_entity>
4866

4967
dmodels_correct_to_default_position:
@@ -74,7 +92,8 @@ dmodels_move_to_frame:
7492
debug: false
7593
definitions: root_entity|animation|timespot
7694
script:
77-
- define animation_data <server.flag[dmodels_data.animations_<[root_entity].flag[dmodel_model_id]>.<[animation]>]||null>
95+
- define model_data <server.flag[dmodels_data.model_<[root_entity].flag[dmodel_model_id]>]>
96+
- define animation_data <server.flag[dmodels_data.animations_<[root_entity].flag[dmodel_model_id]>.<[animation]>]>
7897
- if <[timespot]> > <[animation_data.length]>:
7998
- choose <[animation_data.loop]>:
8099
- case loop:
@@ -89,10 +108,8 @@ dmodels_move_to_frame:
89108
- case hold:
90109
- define timespot <[animation_data.length]>
91110
- flag server dmodels_anim_active.<[root_entity].uuid>:!
111+
- define parentage <map>
92112
- 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
96113
- foreach position|rotation as:channel:
97114
- define relevant_frames <[animator.frames].filter[get[channel].equals[<[channel]>]]>
98115
- define before_frame <[relevant_frames].filter[get[time].is_less_than_or_equal_to[<[timespot]>]].last||null>
@@ -102,35 +119,47 @@ dmodels_move_to_frame:
102119
- if <[after_frame]> == null:
103120
- define after_frame <[before_frame]>
104121
- 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
122+
- define data 0,0,0
109123
- 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:
124+
- define time_range <[after_frame.time].sub[<[before_frame.time]>]>
125+
- if <[time_range]> == 0:
126+
- define time_percent 0
127+
- else:
128+
- define time_percent <[timespot].sub[<[before_frame.time]>].div[<[time_range]>]>
129+
- choose <[before_frame.interpolation]>:
130+
- case catmullrom:
131+
- define before_extra <[relevant_frames].filter[get[time].is_less_than[<[before_frame.time]>]].last||null>
132+
- if <[before_extra]> == null:
133+
- define before_extra <[before_frame]>
134+
- define after_extra <[relevant_frames].filter[get[time].is_more_than[<[after_frame.time]>]].first||null>
135+
- if <[after_extra]> == null:
136+
- define after_extra <[after_frame]>
137+
- define p0 <[before_extra.data].as_location>
138+
- define p1 <[before_frame.data].as_location>
139+
- define p2 <[after_frame.data].as_location>
140+
- define p3 <[after_extra.data].as_location>
141+
- define data <proc[dmodels_catmullrom_proc].context[<[p0]>|<[p1]>|<[p2]>|<[p3]>|<[time_percent]>]>
142+
- case linear:
143+
- define data <[after_frame.data].as_location.sub[<[before_frame.data]>].mul[<[time_percent]>].add[<[before_frame.data]>].xyz>
144+
- case step:
145+
- define data <[before_frame.data]>
146+
- define parent_data 0,0,0
147+
- define parent_id <[model_data.<[part_id]>.parent]>
148+
- while <[parent_id]> != none:
149+
- define new_data <[parentage.<[parent_id]>.<[channel]>]||null>
150+
- if <[new_data]> != null:
151+
- define parent_data <[new_data]>
152+
- while stop
153+
- define parent_id <[model_data.<[parent_id]>.parent]>
154+
- define data <[data].as_location.add[<[parent_data]>]>
155+
- define parentage.<[part_id]>.<[channel]>:<[data]>
156+
- debug log "<[data]> and <[parent_data]> for <[part_id]> and <[model_data.<[part_id]>.parent]||0> in <[channel]>"
157+
- foreach <[root_entity].flag[dmodel_anim_part.<[part_id]>]||<list>> as:ent:
129158
- choose <[channel]>:
130159
- case position:
131-
- teleport <[ent]> <[root_entity].location.add[<[ent].flag[dmodel_def_offset].add[<[data].as_location.div[25.6]>]>]>
160+
- teleport <[ent]> <[root_entity].location.add[<[ent].flag[dmodel_def_offset].add[<[data].div[25.6]>]>]>
132161
- case rotation:
133-
- define radian_rot <[data].as_location.xyz.split[,].parse[to_radians].separated_by[,]>
162+
- define radian_rot <[data].xyz.split[,].parse[to_radians].separated_by[,]>
134163
- adjust <[ent]> armor_pose:[head=<[ent].flag[dmodel_def_pose].as_location.add[<[radian_rot]>].xyz>]
135164

136165
dmodels_catmullrom_get_t:

0 commit comments

Comments
 (0)