Decorator Tool

Berufeng

Member
Jan 29, 2020
18
0
0
This script is for developers who like to use interactable blocks in their builds but don't want players to utilize them for their intended purpose. For example, maybe you are using vertical trapdoors as a fence line, or you want a strictly cosmetic chest or anvil or enchanting table? Or maybe you just want to make your pressure plate table-tops stop clicking when folks get too close?

To use this script, type /decorate. You'll get a special stick you can whack things with to make them decorative, because who doesn't like whacking things with a stick? It's fun AND user-friendly!

To Do:
  • Identify any missed blocks that ought to be "decoratable."
  • Continue entity support with painting and item_frame entities.
  • Allow decorators to lock a campfire with food on it, preventing the food from ever finishing its cooking process.
  • Update for 1.16 blocks (after Paper 1.16 release).

UPDATE 6/25/2020:
- Fix: daylight_dector now correctly toggles state when sneak-right-clicked with the decorator tool.
- Minor bug fix: Added some fallbacks to prevent console errors occurring under certain circumstances when players right-clicked air.

Update History
UPDATE 6/23/2020:
- Added some functionality for the manipulation of armor_stand entities. Making an armor stand decorative will disable its gravity and collisions, and allow the user to move it, rotate it, and toggle its states such as base plate visibility, small/regular size, arms shown/hidden, and invisibility. (Armor stand functionality can be disabled globally in the config.)
- Added a feature that converts player_head blocks into entities (as the helmet slot of an armor stand) automatically.** (This feature can be disabled in the config.)
- Placing a chest next to a decorative chest will now correctly prevent the chests from conjoining. If you wish to make a decorative double chest, simply place the second block before decorating.
- Fixed a few issues where "attached blocks" were erroneously being added/removed as decorative.

**The player_head entity's armor stand will be set to visible by default. This is due to limits of the 'left click' functionality with invisible armor stands, a known issue planned to be fixed in a future update. Once you're finished manipulating the player head entity, you can use the Decorator Tool to make the armor stand invisible.

UPDATE 6/14/2020:
- Added support for jukebox, daylight_detector, bell, cauldron, ender_chest, end_portal_frame, composter, campfire, flower_pot, beacon, and command_block*.

UPDATE 6/12/2020:
- Fixed an egregious error created by renaming the decorator_tool script in the previous update.
- Added support for light_weighted_pressure_plate and heavy_weighted_pressure_plate. (Thanks Kiryll!)

UPDATE 6/7/2020:
- Changed scriptnames to be a bit more consistent.
- Added a config script.
- Added optional narrate to warn players when clicking decorative blocks. (Disabled by default)

Known Issues:
  • player_head entities created with the new functionality are rotated the opposite direction.
  • player_head entities have visible armor stands because of limitations of 'left-click' actions on an invisible armor_stand.
  • Invisible armor_stand entities are immune to left-click actions with the Decorator Tool. For now, make them visible first (using the Decorator Tool item)
  • A decorative command_block will flicker its GUI very briefly when players interact with it.


Here's a link to a haste: https://one.denizenscript.com/haste/71421

Or click Show to show the script in this post.

Code:
Decorator_Tool_Config:
  type: data
  Config:
    # Change to true to warn players when they attempt to interact with decorative blocks.
    # No message by default.
    do_message: false
    message: <dark_red>You cannot use this decorative <context.location.material.translated_name>.
    cooldown: 1s
    # Enables armor stand functionality with Decorator Tool.
    # Disable if using another armor stand editor plugin.
    do_armor_stands: true
    # If true, converts player head blocks to armor stand entities when right-clicked.
    # Generally only useful if armor stand functionality is enabled.
    convert_heads: true
  Data:
    ## The data in this section should not be changed.
    armor_stand_mode: 1/rotate|2/move_x|3/move_z|4/move_y|5/base_plate|6/arms|7/size|8/invisibility
    misc_blocks:
    - loom
    - crafting_table
    - cartography_table
    - anvil
    - chipped_anvil
    - damaged_anvil
    - enchanting_table
    - grindstone
    - smithing_table
    - stonecutter
    - fletching_table
    - light_weighted_pressure_plate
    - heavy_weighted_pressure_plate
    - jukebox
    - daylight_detector
    - bell
    - cauldron
    - ender_chest
    - end_portal_frame
    - composter
    - campfire
    - flower_pot
    - beacon
    - command_block
    - cake

Decorator_Tool_Item:
  type: item
  material: stick
  display name: <blue>Decorator Tool
  lore:
  - Right-click to mark location as decorative.
  - Left-click to unmark location.
  - Shift-right-click to toggle block state.

Decorator_Tool_Command:
  type: command
  name: decorate
  usage: /decorate
  permission: beruscripts.decorator
  description: Gives the player a Decorator Tool.
  script:
      - if !<player.inventory.contains[decorator_tool_item]>:
        - give decorator_tool_item
        - narrate "<aqua>You received a <blue>[Decorator Tool]<aqua>."
        - narrate "<gray>Right-click to decorate, left-click to un-decorate."
        - narrate "<gray>Right-click while sneaking to toggle open/closed."
      - else:
        - take scriptname:decorator_tool_item
        - narrate "<red>Removed your <blue>[Decorator Tool]<red>."

Decorator_Tool_Decorative_Blocks:
  type: world
  debug: false
  events:
    # Decorative Block functionality-- prevents use of blocks marked as decorative.
    on player right clicks block priority:1:
      - if <server.has_flag[decorative_block.<context.location.simple>]||false>:
        - determine passively cancelled
        - if <script[Decorator_Tool_Config].data_key[Config.do_message]> && !<player.has_flag[decorative_block_warn]>:
          - narrate "<script[Decorator_Tool_Config].data_key[Config.message].parsed>"
          - flag <player> decorative_block_warn duration:<script[Decorator_Tool_Config].data_key[Config.cooldown]>
    on player stands on material:
      - if <server.has_flag[decorative_block.<context.location.simple>]||false>:
        - determine cancelled
    # Decorator Tool functionality-- allows use of Decorator Tool item on various blocks.
    on player clicks block with decorator_tool_item:
      - determine passively cancelled
      - if <player.is_sneaking> && <context.click_type> == right_click_block:
        - if <context.location.material.name> == daylight_detector:
          - adjustblock <context.location> switched:<context.location.material.switched.not>
        - else:
          - switch <context.location>
        - stop
      - choose <context.click_type>:
        - case right_click_block:
          - if <context.location.material.name> == player_head && <script[Decorator_Tool_Config].data_key[Config.convert_heads]>:
            - spawn armor_stand[gravity=false;invulnerable=true;collidable=false;armor_pose=head|0,0,0;equipment=air|air|air|<item[player_head].with[skull_skin=<context.location.skull_skin.full>]>] <context.location.center.with_facing_direction[<context.location.direction>].below[1.94]> save:decorative_head
            - flag <entry[decorative_head].spawned_entity> decorative
            - modifyblock <context.location> air
            - stop
          - else if !<context.location.material.is_switchable> && !<context.location.has_inventory> && !<script[Decorator_Tool_Config].data_key[Data.misc_blocks].contains[<context.location.material.name>]> && !<context.location.material.name.ends_with[_bed]>:
            - narrate "<dark_gray>You cannot make <context.location.material.item.formatted> decorative."
            - stop
          - if <server.has_flag[decorative_block.<context.location.simple>]||false>:
            - narrate "<dark_gray>This <gray><context.location.material.translated_name> <dark_gray>is already decorative!"
            - stop
          - narrate "<aqua>Made this <gray><context.location.material.translated_name> <aqua>decorative."
          - flag server decorative_block.<context.location.simple>
          - if <context.location.other_block.simple||null> != null:
            - narrate "<aqua>(Also added adjacent block.)"
            - flag server decorative_block.<context.location.other_block.simple>
        - case left_click_block:
          - if !<server.has_flag[decorative_block.<context.location.simple>]||false>:
            - narrate "<dark_gray>This <gray><context.location.material.translated_name> <dark_gray>is not decorative!"
            - stop
          - narrate "<red>This <gray><context.location.material.translated_name> <red>is no longer decorative."
          - flag server decorative_block.<context.location.simple>:!
          - if <context.location.other_block||null> != null:
            - narrate "<red>(Also removed adjacent block.)"
            - flag server decorative_block.<context.location.other_block.simple>:!
    # Item protection-- Prevents Decorator Tool from being transfered to another inventory.)
    on player drops decorator_tool_item:
      - determine passively cancelled
      - wait 1t
      - take scriptname:decorator_tool_item
    on player clicks in inventory with decorator_tool_item:
      - if <context.clicked_inventory.inventory_type> != PLAYER:
        - determine passively cancelled
        - wait 1t
        - inventory update
    on player clicks decorator_tool_item in inventory:
      - if <context.is_shift_click> && <context.inventory.inventory_type> != PLAYER:
        - determine passively cancelled
        - wait 1t
        - inventory update
    on player drags decorator_tool_item in inventory:
      - if <context.clicked_inventory.inventory_type> != PLAYER:
        - determine passively cancelled
        - wait 1t
        - inventory update
    # If any player breaks a decorative block, alerts them and removes decoration flag.
    on player breaks block priority:1:
      - if <server.has_flag[decorative_block.<context.location.simple>]||false>:
        - narrate "<red>You broke a decorative <context.location.material.translated_name.to_lowercase>."
        - flag server decorative_block.<context.location.simple>:!
        - if <context.location.other_block||null> != null:
          - narrate "<red>(Also removed adjacent block.)"
          - flag server decorative_block.<context.location.other_block.simple>:!
          - if <context.location.material.name> == chest:
            - modifyblock <context.location.other_block> air
    # Decorative Chest functionality-- for placing chests next to existing decorative chests.
    # A chest placed next to a decorative chest will not conjoin to it, nor be decorative itself.
    on player places *chest:
      - if <context.location.other_block||null> != null && <server.has_flag[decorative_block.<context.location.other_block.simple>]>:
        - determine passively cancelled
        - if <player.gamemode> != creative:
          - take iteminhand qty:1
        - wait 1t
        - modifyblock <context.location> <context.material.with[direction=<context.location.direction[<player.location>]>]>

# You can disable armor stand functionality in the Config!
# Set "do_armor_stands" to false.
Decorator_Tool_Armor_Stands:
  type: world
  debug: false
  events:
    on armor_stand damaged priority:1:
      - if <context.entity.has_flag[decorative]>:
        - determine passively cancelled
    on armor_stand damaged by player with:decorator_tool_item:
      - determine passively cancelled
      - if !<script[Decorator_Tool_Config].data_key[Config.do_armor_stands]>:
        - stop
      - if !<context.entity.has_flag[decorative]>:
        - flag <context.entity> decorative
        - adjust <context.entity> gravity:false
        - adjust <context.entity> invulnerable:true
        - adjust <context.entity> collidable:false
        - adjust <context.entity> armor_pose:head|0,0,0
        - narrate "<aqua>Made this <gray>Armor Stand <aqua>decorative. <dark_gray>(Shift-left-click to destroy.)"
        - stop
      - if <player.is_sneaking>:
        - if <player.flag[decorator_tool_delete_entity]||null> == <context.entity.uuid>:
          - flag <player> decorator_tool_delete_entity:!
          - remove <context.entity>
          - narrate "<red>Removed!"
        - else:
          - flag <player> decorator_tool_delete_entity:<context.entity.uuid>
          - adjust <context.entity> glowing:true
          - narrate "<dark_red>Destroy this armor stand? <dark_gray>(Shift-left-click again to confirm.)"
          - wait 3s
          - flag <player> decorator_tool_delete_entity:!
          - adjust <context.entity> glowing:false
      - else:
        - choose <player.flag[decorator_tool_armor_stand_mode]||1>:
          - case 1:
            - teleport <context.entity> <context.entity.location.with_yaw[<context.entity.location.yaw.sub[5]>]>
          - case 2:
            - teleport <context.entity> <context.entity.location.sub[0.02,0,0]>
          - case 3:
            - teleport <context.entity> <context.entity.location.sub[0,0,0.02]>
          - case 4:
            - teleport <context.entity> <context.entity.location.sub[0,0.02,0]>
          - case 5:
            - adjust <context.entity> base_plate:<context.entity.base_plate.not>
          - case 6:
            - adjust <context.entity> arms:<context.entity.arms.not>
          - case 7:
            - adjust <context.entity> is_small:<context.entity.is_small.not>
          - case 8:
            - adjust <context.entity> visible:<context.entity.visible.not>
    on player right clicks armor_stand with:decorator_tool_item:
      - determine passively cancelled
      - if !<script[Decorator_Tool_Config].data_key[Config.do_armor_stands]>:
        - stop
      - if !<context.entity.has_flag[decorative]>:
        - flag <context.entity> decorative
        - adjust <context.entity> gravity:false
        - adjust <context.entity> invulnerable:true
        - adjust <context.entity> collidable:false
        - adjust <context.entity> armor_pose:head|0,0,0
        - narrate "<aqua>Made this <gray>Armor Stand <aqua>decorative. <dark_gray>(Shift-left-click to destroy.)"
        - stop
      - if <player.is_sneaking>:
        - if <player.flag[decorator_tool_armor_stand_mode]> < 8:
          - flag <player> decorator_tool_armor_stand_mode:++
        - else:
          - flag <player> decorator_tool_armor_stand_mode:1
        - actionbar "<blue>[Decorator Tool]: <aqua>Armor Stand Mode - <script[Decorator_Tool_Config].data_key[Data.armor_stand_mode].as_map.get[<player.flag[decorator_tool_armor_stand_mode]>].replace[_].with[ ].to_titlecase>"
      - else:
        - choose <player.flag[decorator_tool_armor_stand_mode]||1>:
          - case 1:
            - teleport <context.entity> <context.entity.location.with_yaw[<context.entity.location.yaw.add[5]>]>
          - case 2:
            - teleport <context.entity> <context.entity.location.add[0.02,0,0]>
          - case 3:
            - teleport <context.entity> <context.entity.location.add[0,0,0.02]>
          - case 4:
            - teleport <context.entity> <context.entity.location.add[0,0.02,0]>
          - case 5:
            - adjust <context.entity> base_plate:<context.entity.base_plate.not>
          - case 6:
            - adjust <context.entity> arms:<context.entity.arms.not>
          - case 7:
            - adjust <context.entity> is_small:<context.entity.is_small.not>
          - case 8:
            - adjust <context.entity> visible:<context.entity.visible.not>
 

mcmonkey

Administrator
Staff member
Helper
(reviewing https://one.denizenscript.com/haste/69318 )
- - give <player> decorator_tool is invalid, and will error in your console. Watch your debug console!
- Use a command script, not the event
- that decorating flag seems redundant... get rid of it.
- consider using priorities on your events to deconflict them.
- Use a map-style flag for the locations instead of a flag list. That is, like, decoration_location.<context.location.simple> as a flag name. This is just more performant with large numbers of decorative blocks in use.
 

Berufeng

Member
Jan 29, 2020
18
0
0
Updated to incorporate all of mcmonkey's suggestions.

Also added functionality:
- Beds of all types are now valid decorative block options.
- Right click with decorator_tool while sneaking to toggle on/off state of applicable blocks, regardless of their "decorative" status.
 

mcmonkey

Administrator
Staff member
Helper
(reviewing https://one.denizenscript.com/haste/69389 )
- Remove the "allowed help" section
- Add a permission node. Just make one up, like berufeng.decorator or something.
- - take decorator_tool this is bad as I mentioned on Discord. Use the scriptname: argument.
- All the stuff about "Decorator mode" and "toggling" seems off. It's just a decorator wand item, there's no "mode" and there's no need to have a "mode".
- <context.location.material.item.formatted.after[ ]> this is some kind of wild hack. Use the MaterialTag.translated_name tag if anything.
 

RedShirt2

New member
Dec 28, 2016
4
0
0
Hey there. Just saw this and I'm going to be working with it. It seems exactly what I've been trying to deal with. I've been building with certain 'villager profession blocks' like barrels and looms, but keep attracting fishermen and shepherds. This is amazing...

Will adding 'cauldron' work? That attracts leather workers.
 

RedShirt2

New member
Dec 28, 2016
4
0
0
on player right clicks block priority:1:
- if <server.has_flag[decorative_block.<context.location.simple>]>:
- determine cancelled

.simple threw an error, while I clicked on other things. Probably need a fallback! Probably.
 

mcmonkey

Administrator
Staff member
Helper
RedShirt2 said:
on player right clicks block priority:1:
- if <server.has_flag[decorative_block.<context.location.simple>]>:
- determine cancelled

.simple threw an error, while I clicked on other things. Probably need a fallback! Probably.
That should not ever cause an error... if it did, please report the full error with a debug log
 

Berufeng

Member
Jan 29, 2020
18
0
0
RedShirt2, I'm not sure this does what you're expecting it to. It might be possible for me to add that functionality, but what this essentially does is prevent players from opening GUI's, toggling block states, etc. It blocks *player* interaction with blocks that are otherwise interactive.
 

Kiryll

Member
Jun 9, 2020
6
0
0
Hi, the heavy-weighted and light-weighted pressure plates are unable to made decorative.
 

Kiryll

Member
Jun 9, 2020
6
0
0
Yo found some more, Im actually not sure if some of these are possible though.
Jukebox, Daylight Sensor, Bell, Cauldron(people can take/put water in it), enderchest(This one is important to me if you can do it :)), Enderportal frame, Composter, Campfire, Pot, Beacon. Also, Occasionally when trying to make a block decorative it gives an error but still works/makes it decorative.
 

Berufeng

Member
Jan 29, 2020
18
0
0
Kiryll said:
Occasionally when trying to make a block decorative it gives an error but still works/makes it decorative.

Can you identify which blocks are causing this to happen? If you can reproduce it, please take note of:
- The script's narrate output.
- The console output (if any).
- The block in question.

Thanks!
 

Kiryll

Member
Jun 9, 2020
6
0
0
Berufeng said:
Kiryll said:
Occasionally when trying to make a block decorative it gives an error but still works/makes it decorative.

Can you identify which blocks are causing this to happen? If you can reproduce it, please take note of:
- The script's narrate output.
- The console output (if any).
- The block in question.

Thanks!

Ok, so this problem was actually told to me by a friend who isn't a part of the denizen community so he asked me to tell you and I just recreated what he did and I think he just misinterpreted what was happening. when left-clicking on a block with the decorating tool, it says that you cant make the block decorative, but if you right click it still makes it decorative.
So, I don't think this is a super big problem, just seems like an aesthetic bug.
https://gyazo.com/e9655d2c5160334132459eeef43f5b20
Link to a picture of my chat
 

Berufeng

Member
Jan 29, 2020
18
0
0
Kiryll said:
So, I don't think this is a super big problem, just seems like an aesthetic bug.
https://gyazo.com/e9655d2c5160334132459eeef43f5b20
Link to a picture of my chat

Lol.... no, this is just a case of your friend misinterpreting plain English. "This Loom is not decorative" means that the loom is not decorative... meaning it hasn't been made decorative by the Decorator Tool yet. By left-clicking, you are trying to remove the decorative status from the loom, so you receive an error message which tells you "This isn't decorative. Why are you trying to make it not decorative?"
 

Kiryll

Member
Jun 9, 2020
6
0
0
Berufeng said:
Kiryll said:
So, I don't think this is a super big problem, just seems like an aesthetic bug.
https://gyazo.com/e9655d2c5160334132459eeef43f5b20
Link to a picture of my chat

Lol.... no, this is just a case of your friend misinterpreting plain English. "This Loom is not decorative" means that the loom is not decorative... meaning it hasn't been made decorative by the Decorator Tool yet. By left-clicking, you are trying to remove the decorative status from the loom, so you receive an error message which tells you "This isn't decorative. Why are you trying to make it not decorative?"

"Ohh lmao, me and him are both dumb haha"
 

RedShirt2

New member
Dec 28, 2016
4
0
0
Berufeng said:
RedShirt2, I'm not sure this does what you're expecting it to. It might be possible for me to add that functionality, but what this essentially does is prevent players from opening GUI's, toggling block states, etc. It blocks *player* interaction with blocks that are otherwise interactive.

OK, I see that. So to be clear what I'm looking for: eg: Place a loom, but disable the loom so Sheppards don't spawn.

Perhaps it's a matter of replacing a loom block with a fake loom block, but that's probably outside the scope of your script...

Thanks
 

RedShirt2

New member
Dec 28, 2016
4
0
0
mcmonkey said:
RedShirt2 said:
on player right clicks block priority:1:
- if <server.has_flag[decorative_block.<context.location.simple>]>:
- determine cancelled

.simple threw an error, while I clicked on other things. Probably need a fallback! Probably.
That should not ever cause an error... if it did, please report the full error with a debug log

- if <server.has_flag[decorative_block.<context.location.simple>]>:
just needs a fallback for when you aren't using the decorator...
- if <server.has_flag[decorative_block.<context.location.simple>]||false>: