KubeJS

KubeJS

61M Downloads

Speed from modified tool tier doesn't seem to apply

MaxNeedsSnacks opened this issue · 6 comments

commented

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>
commented

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.

commented

Damnit, of course Minecraft does it that way...

Guess this'll need some fixin with Mixin, then

commented

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!");
		}
	}
commented

Does this issue also effect tierOptions.uses? I can't get it to work on any pickaxe

commented

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
}
})
})

commented

Hello, does solution exsist?