Speed from modified tool tier doesn't seem to apply
MaxNeedsSnacks opened this issue · 6 comments
Discussed in #192
Originally posted by Fakeziinho September 4, 2021
I was trying to make a script that changed the miningSpeed`of netherite pickaxe, it just didn't work, could someone help me what I did wrong.
onEvent('item.modification', e => {
e.modify('minecraft:netherite_pickaxe', t => {
t.tier = tierOptions => {
tierOptions.speed = 16.0
}
})
})
```</div>
I guess its based on this:
protected DiggerItem(float f, float g, Tier tier, Set<Block> set, Item.Properties properties) {
super(tier, properties);
this.blocks = set;
this.speed = tier.getSpeed();
this.attackDamageBaseline = f + tier.getAttackDamageBonus();
Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
builder.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Tool modifier", (double)this.attackDamageBaseline, AttributeModifier.Operation.ADDITION));
builder.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Tool modifier", (double)g, AttributeModifier.Operation.ADDITION));
this.defaultModifiers = builder.build();
}
Where minecraft decides to store this.speed
into an own variable to use it later on instead of using tier.getSpeed()
. Changing the speed of the tier works but it does not take any affect for the actual item. Constructor of DiggerItem
gets called then item.modification
happens and the tier is changed but speed
don't care.
I guess KubeJS needs a system to cover these things maybe? Like changing a tier will result into re-initialize some data? Maybe something like register a tier-callback and if the tier is changed kubejs executes all registered callbacks. Could be helpful for adding support for other mods?
Besides speed
there are other things too like attackdamage, attackspeed which has the same problem. For attackdamage and attackspeed kubejs needs to change the AttributeModifiers
too which is kinda ugly. I played around with it but not that much.
Damnit, of course Minecraft does it that way...
Guess this'll need some fixin with Mixin, then
Just a quick example from above. Maybe the solution is worth. Example implemented for speed
and for the attackBonus
for TieredItem
's. With attackBonus
resets the default AttributeModifiers
too.
public class PropertyResets {
public static final PropertyResets INSTANCE = new PropertyResets();
static {
INSTANCE.register(TierChangePropertyResets::SpeedPropertyReset);
INSTANCE.register(TierChangePropertyResets::AttackDamageReset);
}
private final Map<Class<?>, Map<Class<?>, ArrayList<BiConsumer<Object, Object>>>> resetListeners = new HashMap<>();
private PropertyResets() {
}
@SuppressWarnings("unchecked")
public <T, E> void register(BiConsumer<T, E> consumer) {
Objects.requireNonNull(consumer);
Pair<Class<T>, Class<E>> classes = getClasses(consumer);
ArrayList<BiConsumer<Object, Object>> listeners = getListeners(classes.getLeft(), classes.getRight());
listeners.add((BiConsumer<Object, Object>) consumer);
}
public void invoke(Object modifiable, Object oldData) {
try {
resetListeners.forEach((leftClass, value) -> {
if (!leftClass.isAssignableFrom(modifiable.getClass())) {
return;
}
value.forEach((rightClass, consumers) -> {
if (!rightClass.isAssignableFrom(oldData.getClass())) {
return;
}
consumers.forEach(c -> c.accept(modifiable, oldData));
});
});
} catch (Exception e) {
ScriptType.STARTUP.console.error(e);
}
}
private <T, E> ArrayList<BiConsumer<Object, Object>> getListeners(Class<T> first, Class<E> second) {
Map<Class<?>, ArrayList<BiConsumer<Object, Object>>> map = resetListeners.computeIfAbsent(first, aClass -> new HashMap<>());
return map.computeIfAbsent(second, aClass -> new ArrayList<>());
}
@SuppressWarnings("unchecked")
private <T, E> Pair<Class<T>, Class<E>> getClasses(BiConsumer<T, E> consumer) {
Class<?>[] classes = TypeResolver.resolveRawArguments(BiConsumer.class, consumer.getClass());
Class<T> classT = (Class<T>) classes[0];
Class<E> classE = (Class<E>) classes[1];
return new ImmutablePair<>(classT, classE);
}
}
public class TierChangePropertyResets {
public static void SpeedPropertyReset(DiggerItemKJS item, Tier oldTier) {
DiggerItem vanilla = (DiggerItem) item;
if (oldTier.getSpeed() == vanilla.getTier().getSpeed()) {
return;
}
item.setSpeedKJS(vanilla.getTier().getSpeed());
}
public static void AttackDamageReset(Tier oldTier, TieredItem item) {
// TODO refactor if accepted - combine sword and digger `setAttackDamageBaseline`
if (oldTier.getAttackDamageBonus() == item.getTier().getAttackDamageBonus()) {
return;
}
if (!(item instanceof DiggerItem)) {
return;
}
DiggerItemKJS asKJS = (DiggerItemKJS) item;
float oldDamage = asKJS.getAttackDamageBaseline() - oldTier.getAttackDamageBonus();
float newDamage = oldDamage + item.getTier().getAttackDamageBonus();
asKJS.setAttackDamageBaseline(newDamage);
// please ignore magic number pls
AttributeModifierHelper.setDefaultValue(item, Attributes.ATTACK_DAMAGE, UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF"), newDamage);
}
}
And invoked here for ItemModificationProperties
public void setTier(Consumer<ModifiedToolTier> c) {
if (item instanceof TieredItemKJS) {
Tier oldTier = ((TieredItemKJS) item).getTierKJS();
ModifiedToolTier t = new ModifiedToolTier(oldTier);
c.accept(t);
((TieredItemKJS) item).setTierKJS(t);
PropertyResets.INSTANCE.invoke(item, oldTier);
} else {
throw new IllegalArgumentException("Item is not a tool/tiered item!");
}
}
Does this issue also effect tierOptions.uses? I can't get it to work on any pickaxe
Hello, Are you find the solution ?How do you write ? Can you give a example ?
The below I test to modify the damage of diamond sword, but it does's work.....
onEvent('item.modification', event => {
event.modifyTier('minecraft:diamond_sword', item => {
item.tier = tierOptions => {
tierOptions.attackDamageBonus = 20.0
}
})
})