Skip to content

Commit 3a0e574

Browse files
committed
dmodels_command
1 parent 922ff08 commit 3a0e574

File tree

3 files changed

+208
-2
lines changed

3 files changed

+208
-2
lines changed

scripts/dmodels_command.dsc

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
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+
dmodels_cmd_data:
7+
type: data
8+
debug: false
9+
# Note: must not include the '.' symbol
10+
# (both for security reasons, and because that's the flag submapping key symbol)
11+
valid_chars: abcdefghijklmnopqrstuvwxyz0123456789_-/
12+
13+
dmodels_command:
14+
type: command
15+
debug: false
16+
name: dmodels
17+
usage: /dmodels [load/loadall/spawn/remove/animate/stopanimate]
18+
description: Manages Denizen Models.
19+
permission: dmodels.help
20+
tab completions:
21+
1: <proc[dmodels_tab_1]>
22+
2: <context.args.proc[dmodels_tab_2]>
23+
data:
24+
load_example: <&[error]>'path' should be a valid file name, for example if you have <&[emphasis]>data/dmodels/example.bbmodel<&[error]>, you should do: <&[warning]>/dmodels load example
25+
script:
26+
- choose <context.args.first||help>:
27+
- case load:
28+
- if !<player.has_permission[dmodels.load]>:
29+
- narrate "<&[error]>You do not have permission for that."
30+
- stop
31+
- if !<context.args.get[2].exists>:
32+
- narrate "<&[warning]>/dmodels load [path] <&[error]>- loads a model from file based on filename"
33+
- narrate <script.parsed_key[load_example]>
34+
- stop
35+
- define path <context.args.get[2]>
36+
- if !<[path].to_lowercase.matches_character_set[<script[dmodels_cmd_data].data_key[valid_chars]>]>:
37+
- narrate "<&[error]>Given file path has an invalid format. Double-check that you entered the exact name, without root path, and without the '.bbmodel' suffix."
38+
- narrate <script.parsed_key[load_example]>
39+
- stop
40+
- if !<util.has_file[data/dmodels/<[path]>.bbmodel]>:
41+
- narrate "<&[error]>No file exists at the given path. Double-check that you entered the exact name, without root path, and without the '.bbmodel' suffix."
42+
- narrate <script.parsed_key[load_example]>
43+
- stop
44+
- if <server.has_flag[dmodels_data.model_<[path]>]>:
45+
- narrate "<&[base]>That model is already loaded and will be reloaded..."
46+
- else:
47+
- narrate "<&[base]>Loading that model..."
48+
- debug log "[DModels] <&[emphasis]><player.name||server> <&[base]>is loading a model file: <[path].custom_color[emphasis]>"
49+
- ~run dmodels_load_bbmodel def.model_name:<[path]>
50+
- if <server.has_flag[dmodels_data.model_<[path]>]>:
51+
- narrate "<&[base]>Model <[path].custom_color[emphasis]> loaded."
52+
- else:
53+
- narrate "<&[error]>Unable to load that model."
54+
- case loadall:
55+
- if !<player.has_permission[dmodels.loadall]>:
56+
- narrate "<&[error]>You do not have permission for that."
57+
- stop
58+
- ~run dmodels_gather_folder def.folder:data/dmodels save:list
59+
- define files <entry[list].created_queue.determination.first>
60+
- narrate "<&[base]>Loading <[files].size.custom_color[emphasis]> files..."
61+
- debug log "[DModels] <&[emphasis]><player.name||server> <&[base]>is loading <[files].size.custom_color[emphasis]> model files: <[files].formatted.custom_color[emphasis]>"
62+
- ~run dmodels_multi_load def.list:<[files]>
63+
- narrate <&[base]>Done!
64+
- case spawn:
65+
- if !<player.has_permission[dmodels.spawn]>:
66+
- narrate "<&[error]>You do not have permission for that."
67+
- stop
68+
- if !<context.args.get[2].exists>:
69+
- narrate "<&[warning]>/dmodels spawn [model] <&[error]>- spawns a model at your position (must be loaded)"
70+
- stop
71+
- define model <context.args.get[2]>
72+
- if !<[model].to_lowercase.matches_character_set[<script[dmodels_cmd_data].data_key[valid_chars]>]>:
73+
- narrate "<&[error]>Given model name has an invalid format."
74+
- stop
75+
- if !<server.has_flag[dmodels_data.model_<[model]>]>:
76+
- narrate "<&[error]>No such model exists, or that model has never been loaded."
77+
- stop
78+
- run dmodels_spawn_model def.model_name:<[model]> def.location:<player.location> save:result
79+
- define spawned <entry[result].created_queue.determination.first||null>
80+
- if !<[spawned].is_truthy>:
81+
- narrate "<&[error]>Spawning failed?"
82+
- stop
83+
- flag player spawned_model_<[model]>:<[spawned]>
84+
- narrate "<&[base]>Spawned model <[model].custom_color[emphasis]> with root entity <[spawned].uuid.custom_color[emphasis]>, stored to player flag '<&[emphasis]>spawned_dmodel_<[model]><&[base]>'"
85+
- case remove:
86+
- if !<player.has_permission[dmodels.remove]>:
87+
- narrate "<&[error]>You do not have permission for that."
88+
- stop
89+
- inject dmodels_get_target
90+
- define model <[target].flag[dmodel_model_id]>
91+
- run dmodels_delete def.root_entity:<[target]>
92+
- narrate "<&[base]>Removed a spawned copy of model <[model].custom_color[emphasis]>."
93+
- case animate:
94+
- if !<player.has_permission[dmodels.animate]>:
95+
- narrate "<&[error]>You do not have permission for that."
96+
- stop
97+
- if !<context.args.get[2].exists>:
98+
- narrate "<&[warning]>/dmodels animate [animation] <&[error]>- causes the closest real-spawned model to start playing the given animation"
99+
- stop
100+
- define animation <context.args.get[2]>
101+
- if !<[animation].to_lowercase.matches_character_set[<script[dmodels_cmd_data].data_key[valid_chars]>]>:
102+
- narrate "<&[error]>Given animation name contains an invalid format."
103+
- stop
104+
- inject dmodels_get_target
105+
- if !<server.has_flag[dmodels_data.animations_<[target].flag[dmodel_model_id]>.<[animation]>]||null>:
106+
- narrate "<&[error]>Unknown animation name given. Available animations: <&[emphasis]><server.flag[dmodels_data.animations_<[target].flag[dmodel_model_id]>].keys.formatted>"
107+
- run dmodels_animate def.root_entity:<[target]> def.animation:<[animation]>
108+
- narrate "<&[base]>Model <[target].flag[dmodel_model_id].custom_color[emphasis]> is now playing animation <[animation].custom_color[emphasis]>"
109+
- case stopanimate:
110+
- if !<player.has_permission[dmodels.stopanimate]>:
111+
- narrate "<&[error]>You do not have permission for that."
112+
- stop
113+
- inject dmodels_get_target
114+
- if !<[target].has_flag[dmodels_animation_id]>:
115+
- narrate "<&[base]>Your nearest model is not animating currently."
116+
- stop
117+
- run dmodels_end_animation def.root_entity:<[target]>
118+
- narrate "<&[base]>Animation stopped."
119+
# help
120+
- default:
121+
- if <player.has_permission[dmodels.load]||true>:
122+
- narrate "<&[warning]>/dmodels load [path] <&[error]>- loads a model from file based on filename"
123+
- if <player.has_permission[dmodels.loadall]||true>:
124+
- narrate "<&[warning]>/dmodels loadall <&[error]>- loads all models in the source folder"
125+
- if <player.has_permission[dmodels.spawn]||true>:
126+
- narrate "<&[warning]>/dmodels spawn [model] <&[error]>- spawns a model at your position (must be loaded)"
127+
- if <player.has_permission[dmodels.remove]||true>:
128+
- narrate "<&[warning]>/dmodels remove <&[error]>- removes the closest real-spawned model to your location"
129+
- if <player.has_permission[dmodels.animate]||true>:
130+
- narrate "<&[warning]>/dmodels animate [animation] <&[error]>- causes the closest real-spawned model to start playing the given animation"
131+
- if <player.has_permission[dmodels.stopanimate]||true>:
132+
- narrate "<&[warning]>/dmodels stopanimate <&[error]>- causes the closest real-spawned model to stop animating"
133+
- narrate "<&[warning]>/dmodels help <&[error]>- this help output"
134+
135+
dmodels_get_target:
136+
type: task
137+
debug: false
138+
script:
139+
- define target <player.location.find_entities[dmodel_part_stand].within[10].filter[has_flag[dmodel_model_id]].first||null>
140+
- if !<[target].is_truthy>:
141+
- narrate "<&[error]>No spawned model is close enough. Are you near a model? If so, are you sure it's an independent real-spawned model (as opposed to fake-spawned, or separately attached)?"
142+
- stop
143+
144+
dmodels_tab_1:
145+
type: procedure
146+
debug: false
147+
script:
148+
- define list <list>
149+
- foreach load|loadall|spawn|remove|animate|stopanimate|help as:key:
150+
- if <player.has_permission[<[key]>]||true>:
151+
- define list:->:<[key]>
152+
- determine <[list]>
153+
154+
dmodels_tab_2:
155+
type: procedure
156+
debug: false
157+
definitions: args
158+
script:
159+
- if <[args].first> == load && <player.has_permission[dmodels.load]||true>:
160+
- define path <[args].get[2]||>
161+
- if !<[path].to_lowercase.matches_character_set[<script[dmodels_cmd_data].data_key[valid_chars]>]>:
162+
- determine <list>
163+
- if <[path].contains[/]>:
164+
- define path <[path].before_last[/]>
165+
- else:
166+
- define path <empty>
167+
- determine <util.list_files[data/dmodels/<[path]>].parse[before_last[.bbmodel]]||<list>>
168+
- else if <[args].first> == spawn && <player.has_permission[dmodels.spawn]||true>:
169+
- determine <server.flag[dmodels_data].keys.filter[starts_with[model_]].parse[after[model_]]>
170+
- else if <[args].first> == animate && <player.has_permission[dmodels.animate]||true>:
171+
- define target <player.location.find_entities[dmodel_part_stand].within[10].filter[has_flag[dmodel_model_id]].first||null>
172+
- if !<[target].is_truthy>:
173+
- determine <list>
174+
- determine <server.flag[dmodels_data.animations_<[target].flag[dmodel_model_id]>].keys>
175+
- determine <list>
176+
177+
dmodels_gather_folder:
178+
type: task
179+
debug: false
180+
definitions: folder
181+
script:
182+
- define output <list>
183+
- foreach <util.list_files[<[folder]>]||<list>> as:file:
184+
- define full_file <[folder]>/<[file]>
185+
- if <[file].ends_with[.bbmodel]>:
186+
- define clean_name <[full_file].after[data/dmodels/].before_last[.bbmodel]>
187+
- if !<[clean_name].to_lowercase.matches_character_set[<script[dmodels_cmd_data].data_key[valid_chars]>]>:
188+
- narrate "<&[error]>Skipping file <[file].custom_color[emphasis]> due to invalid file name format"
189+
- else:
190+
- define output:->:<[clean_name]>
191+
- else if !<[file].contains[.]>:
192+
- run dmodels_gather_folder def.folder:<[full_file]> save:subdata
193+
- define output:|:<entry[subdata].created_queue.determination.first>
194+
- determine <[output]>

scripts/dmodels_loader.dsc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dmodels_multi_load:
1313
- foreach <[list]> as:model:
1414
- run dmodels_multiwaitable_load def.key:<[key]> def.model:<[model]>
1515
# Ensure all loads are done before ending the task
16-
- waituntil rate:1t max:5m <server.flag[dmodels_data.temp_<[key]>.filewrites].is_empty||true>
16+
- waituntil rate:1t max:5m <server.flag[dmodels_data.temp_<[key]>.multiload].is_empty||true>
1717
# Cleanup
1818
- flag server dmodels_data.temp_<[key]>:!
1919

@@ -195,7 +195,7 @@ dmodels_load_bbmodel:
195195
- flag server dmodels_data.model_<[model_name]>.<[outline.uuid]>:<[outline]>
196196
- if <[overrides_changed]>:
197197
- define override_file_json <[override_item_data].to_json[native_types=true;indent=4].utf8_encode>
198-
- flag server dmodels_temp_item_file:<[override_file_json].utf8_encode> expire:1h
198+
- flag server dmodels_temp_item_file:<[override_file_json]> expire:1h
199199
- waituntil rate:1t max:15s !<server.has_flag[dmodels_data.temp_<[model_name]>.filewrites.<[override_item_filepath].escaped>]>
200200
- run dmodels_multiwaitable_filewrite def.key:<[model_name]> def.path:<[override_item_filepath]> def.data:<[override_file_json]>
201201
# Ensure all filewrites are done before ending the task

scripts/dmodels_main.dsc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@
3939
# 5: Spawn your model and control it using the Denizen scripting API documented below
4040
#
4141
# #########
42+
# Commands:
43+
# /[Command] - [Permission] - [Description]
44+
# /dmodels - "dmodels.help" - Root command entry
45+
# /dmodels help - "dmodels.help" - Shows help information about the dModels command
46+
# /dmodels load [path] - "dmodels.load" - Loads a single model based on model file name input
47+
# /dmodels loadall - "dmodels.loadall" - Loads all models in the models folder
48+
# /dmodels spawn - "dmodels.spawn" - Spawns a static instance of a model at your location
49+
# /dmodels remove - "dmodels.remove" - Removes whichever real-spawned model is closest to your location
50+
# /dmodels animate [animation] - "dmodels.animate" - Causes your nearest real-spawned model to play the specified animation
51+
# /dmodels stopanimate - "dmodels.stopanimate" - Causes your nearest real-spawned model to stop animating
52+
#
53+
# #########
4254
#
4355
# API usage examples:
4456
# # First load a model (in advance, not every time - you can use '/ex' to do this once after adding or modifying the .bbmodel file)

0 commit comments

Comments
 (0)