Skip to content

Commit f828d45

Browse files
authored
Debug Stick example script (#314)
* add debug stick with comments * minor format change
1 parent b62945a commit f828d45

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

examples/assets/groovyscriptdev/lang/en_us.lang

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ enchantment.level.17=XVII
2020
enchantment.level.18=XVIII
2121
enchantment.level.19=XIX
2222
enchantment.level.20=XX
23+
24+
# Debug Stick Information
25+
item.groovyscriptdev.debug_stick.name=Debug Stick
26+
item.groovyscriptdev.debug_stick.empty=%s has no properties
27+
item.groovyscriptdev.debug_stick.update="%s" to %s
28+
item.groovyscriptdev.debug_stick.select=selected "%s" (%s)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"parent": "item/generated",
3+
"textures": {
4+
"layer0": "minecraft:items/stick"
5+
}
6+
}

examples/preInit/DebugTool.groovy

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//
2+
/*
3+
* This is an example of high end custom content.
4+
*
5+
* This code creates the Debug Stick from 1.13+ in 1.12.2,
6+
* which allows easily changing the blockstate in-world.
7+
* A functional difference from the 1.13+ version is that this
8+
* can also function in survival mode, and has less bugs.
9+
*
10+
* A number of comments have been added to help understand it.
11+
*/
12+
13+
// import the classes that are used in this script
14+
import com.cleanroommc.groovyscript.compat.content.GroovyItem
15+
import net.minecraft.block.properties.IProperty
16+
import net.minecraft.util.EnumActionResult
17+
import net.minecraft.util.text.ITextComponent
18+
import net.minecraft.util.text.TextComponentTranslation
19+
import net.minecraftforge.event.entity.player.PlayerInteractEvent
20+
21+
// a number of static methods have been created as shorthand
22+
23+
/**
24+
* @return the next blockstate in the series of the focused property, respective of direction
25+
*/
26+
static <T extends Comparable<T>> IBlockState cycleState(IBlockState state, IProperty<T> property, boolean invert) {
27+
state.withProperty(property, getRelative(property.getAllowedValues(), state.getValue(property), invert))
28+
}
29+
30+
/**
31+
* the next or prior type relative to the target
32+
*/
33+
static <T> T getRelative(Collection<T> allowedValues, T currentValue, boolean invert) {
34+
int index = allowedValues.findIndexOf({ it == currentValue })
35+
if (index === -1) return allowedValues[0]
36+
int target = index + (invert ? 1 : -1)
37+
allowedValues[allowedValues.size() <= target ? 0 : target]
38+
}
39+
40+
/**
41+
* get the name of the property for the blockstate
42+
*/
43+
static <T extends Comparable<T>> String getPropertyName(IBlockState state, IProperty<T> property) {
44+
property.getName(state.getValue(property))
45+
}
46+
47+
/**
48+
* send a status message to the player - it appears above the hotbar
49+
*/
50+
static void message(EntityPlayer player, ITextComponent message) {
51+
player.sendStatusMessage(message, true)
52+
}
53+
54+
/**
55+
* rotate through the states of the property or through type of property being targeted for the given blockstate interacted with
56+
*/
57+
static void handleInteraction(EntityPlayer player, World world, BlockPos pos, boolean shouldCycleState, ItemStack debugStick) {
58+
def state = world.getBlockState(pos)
59+
def block = state.getBlock()
60+
def collection = state.getPropertyKeys()
61+
def key = block.getRegistryName().toString()
62+
if (collection.isEmpty()) {
63+
message(player, new TextComponentTranslation(debugStick.getTranslationKey() + ".empty", key))
64+
return
65+
}
66+
def data = debugStick.getTagCompound()
67+
if (data == null) {
68+
data = nbt()
69+
debugStick.setTagCompound(data)
70+
}
71+
72+
def targetBlock = data.getString(key)
73+
74+
def property = state.getProperties().keySet().findResult({ it.getName() == targetBlock ? it : null })
75+
76+
if (shouldCycleState) {
77+
if (property == null) {
78+
property = collection.iterator().next()
79+
}
80+
def blockstate = cycleState(state, property, player.isSneaking())
81+
world.setBlockState(pos, blockstate, 2 | 8 | 16)
82+
message(player, new TextComponentTranslation(debugStick.getTranslationKey() + ".update", property.getName(), getPropertyName(blockstate, property)))
83+
} else {
84+
property = getRelative(collection, property, player.isSneaking())
85+
def newString = property.getName()
86+
data.setString(key, newString)
87+
message(player, new TextComponentTranslation(debugStick.getTranslationKey() + ".select", newString, getPropertyName(state, property)))
88+
}
89+
}
90+
91+
/**
92+
* this extends GroovyItem to make it easier add custom effects and register it.
93+
* any other class could be used instead
94+
*/
95+
class ItemDebugStick extends GroovyItem {
96+
97+
/**
98+
* sets the name of this item - a required part of GroovyItem
99+
* will check the "groovyscriptdev/models/item/debug_stick.json" file for its texture
100+
* which has been edited to point to the texture of "minecraft:stick"
101+
*/
102+
ItemDebugStick() {
103+
super('debug_stick')
104+
}
105+
106+
/**
107+
* ensure that the debug stick cannot mine blocks in survival
108+
*/
109+
float getDestroySpeed(ItemStack stack, IBlockState state) {
110+
0.0f
111+
}
112+
113+
/**
114+
* you can override methods, this overrides interacting with the item
115+
*/
116+
EnumActionResult onItemUseFirst(EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, EnumHand hand) {
117+
if (!world.isRemote) DebugTool.handleInteraction(player, world, pos, true, player.getHeldItem(hand))
118+
EnumActionResult.SUCCESS
119+
}
120+
121+
/**
122+
* the debug stick should not destroy blocks in creative
123+
*/
124+
boolean canDestroyBlockInCreative(World world, BlockPos pos, ItemStack stack, EntityPlayer player) {
125+
false
126+
}
127+
}
128+
129+
// this creates and registers the custom item
130+
new ItemDebugStick()
131+
.setCreativeTab(creativeTab('tools')) // sets the tab the debug stick is added to
132+
// these three methods are unique to GroovyItem
133+
.setRarity(EnumRarity.EPIC) // sets the color of the name
134+
.setEnchantedEffect() // makes the item have the shimmer effect as if it was enchanted
135+
.register() // the same as `content.registerItem(item.getRegistryName().getPath(), item)`
136+
137+
138+
// since there isnt a method to check for "left click block" (only "destroy block") in item, we use an event
139+
// this could also occur in postInit! further, if it was in postInit it could be reloaded.
140+
event_manager.listen { PlayerInteractEvent.LeftClickBlock event ->
141+
def player = event.getEntityPlayer()
142+
if (player.world.isRemote) return
143+
def stack = player.getHeldItem(event.getHand())
144+
if (stack.getItem() instanceof ItemDebugStick) { // could also do `stack in item('groovyscriptdev:debug_stick')`
145+
// only operate if in creative or if its not immediately after a prior swing
146+
if (player.isCreative() || player.ticksSinceLastSwing != 1) handleInteraction(player, player.world, event.getPos(), false, stack)
147+
event.setCanceled(true) // cancel the normal operations
148+
}
149+
}

0 commit comments

Comments
 (0)