Better Combat [Fabric & Forge]

Better Combat [Fabric & Forge]

21M Downloads

Scale Attack Range with Pehkui's entity scale

bassistracer opened this issue ยท 16 comments

commented

Just an idea for something long down the road, but, I figured this is probably one of the easier ways to add compatibility between Better Combat and Pehkui.
So, if Pehkui doubles your "block reach" by 2, your attack range likewise multiplies by 2 -- and vise versa.
The reason why I mention "block reach" specifically is because it's usually calculated when growing or shrinking players' base height.
Assuming this wouldn't be a total pain in the arse to program, that is. Thanks for reading.

commented

Looks like the crash is because you misspelt pehkui as pekhui in the Identifier. Also since Pehkui has a Forge version you don't need to keep the compat Fabric-specific.

commented

I created a Pekhui integration branch, using the reflection based solution.

Unfortunately I am getting the following crash:

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "obj" is null
	at java.base/java.lang.reflect.Method.invoke(Method.java:561)
	at net.bettercombat.fabric.client.PekhuiIntegration.getScale(PekhuiIntegration.java:60)
	at net.bettercombat.fabric.client.PekhuiIntegration.getScale(PekhuiIntegration.java:51)
	at net.bettercombat.fabric.PlatformClientImpl.getEntityScale(PlatformClientImpl.java:9)
	at net.bettercombat.PlatformClient.getEntityScale(PlatformClient.java)
	at net.bettercombat.client.collision.TargetFinder.findAttackTargetResult(TargetFinder.java:30)
	at net.minecraft.client.render.debug.DebugRenderer.handler$bce000$renderColliderDebug(DebugRenderer.java:554)
	at net.minecraft.client.render.debug.DebugRenderer.render(DebugRenderer.java:132)
	at net.minecraft.client.render.WorldRenderer.render(WorldRenderer.java:1182)
	at net.minecraft.client.render.GameRenderer.renderWorld(GameRenderer.java:1024)
	at net.minecraft.client.render.GameRenderer.render(GameRenderer.java:833)
	at net.minecraft.client.MinecraftClient.render(MinecraftClient.java:1101)
	at net.minecraft.client.MinecraftClient.run(MinecraftClient.java:751)
	at net.minecraft.client.main.Main.main(Main.java:220)
	at net.minecraft.client.main.Main.main(Main.java:56)
	at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:461)
	at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74)
	at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23)
	at net.fabricmc.devlaunchinjector.Main.main(Main.java:86)
	at dev.architectury.transformer.TransformerRuntime.main(TransformerRuntime.java:217)

I am really not sure if reflection based solution can be stable in the long term.

Is there no way to provide the scale values via any Vanilla API?

commented

Wow big mistake from my part, sorry!
Thanks for the help!

commented

Hello!
Theoretically I could scale the attack range of the player using the scale from Pekhui.
Unfortunately that mod doesn't seem to offer any attribute I can rely on without an explicit dependency.

commented

Hello! Theoretically I could scale the attack range of the player using the scale from Pekhui. Unfortunately that mod doesn't seem to offer any attribute I can rely on without an explicit dependency.

That's strange -- usually something like this should just make it an optional dependency as opposed to a mandatory one. I'll ask around and see if there's any way to just make it the former.

commented

Just to clarify:
I don't want to introduce ANY gradle dependency on Pehkui.

On the other hand I am open for communicating with that mod via Minecraft's Vanilla API. If there is a scale EntityAttribute Pehkui introduces, I could use the value of that. However their developer documentation contains no information in this regard.
Nor does the developer seem to have a Discord server I was able to find.

commented

Since you mentioned using attributes, instead of using Pehkui directly it would probably be better if you were to make use of Reach-Entity-Attributes, which Pehkui has compat code for to adjust the attribute values based on one's scale. Would also improve compat with other Fabric mods that adjust attack and block reach.

commented

Hi!
Thanks for the reply!:)
Better Combat has a custom target lookup and collision detection code.
I think REA would not help, because Better Combat is independent from Vanilla targeting mechanics.

I think the correct solution is for Better Combat to obtain the scale (float value) of the player, so the OBB used for weapon collision could be scaled with it.

What do you think, what would be a good way to obtain this?

commented

I would not consider the following as a good way in the slightest, but, a way to obtain a scale without a dependency would be something equivalent to this terrible chunk of reflection:

Show/Hide Reflection
private static final Method GET_SCALE_DATA;
private static final Method GET_SCALE;
private static final Map<Identifier, Object> SCALE_TYPES;

static
{
	Method getScaleDataMethod = null;
	Method getScaleMethod = null;
	Map<Identifier, Object> scaleTypes = null;
	
	if (FabricLoader.getInstance().isModLoaded("pehkui"))
	{
		try
		{
			Class<?> scaleTypeClass = Class.forName("virtuoel.pehkui.api.ScaleType");
			Class<?> scaleDataClass = Class.forName("virtuoel.pehkui.api.ScaleData");
			Class<?> scaleRegistriesClass = Class.forName("virtuoel.pehkui.api.ScaleRegistries");
			Field scaleTypesField = scaleRegistriesClass.getField("SCALE_TYPES");
			
			getScaleDataMethod = scaleTypeClass.getMethod("getScaleData", Entity.class);
			getScaleMethod = scaleDataClass.getMethod("getScale", float.class);
			scaleTypes = (Map<Identifier, Object>) scaleTypesField.get(null);
		}
		catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException e)
		{
			getScaleDataMethod = null;
			getScaleMethod = null;
			scaleTypes = null;
		}
	}
	
	GET_SCALE_DATA = getScaleDataMethod;
	GET_SCALE = getScaleMethod;
	SCALE_TYPES = scaleTypes;
}

public static float getScale(Entity entity, Identifier scaleId)
{
	return getScale(entity, scaleId, 1.0F);
}

public static float getScale(Entity entity, Identifier scaleId, float tickDelta)
{
	if (GET_SCALE_DATA != null && GET_SCALE != null && SCALE_TYPES != null)
	{
		try
		{
			return (float) GET_SCALE.invoke(GET_SCALE_DATA.invoke(SCALE_TYPES.get(scaleId), entity), tickDelta);
		}
		catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
		{
			return 1.0F;
		}
	}
	
	return 1.0F;
}
commented

Thanks for all this code. Yes this looks rather suboptimal.
Just out of curiosity, what is the reason behind not storing the scale in an entity attribute?

That way any mod could add compatibility easily.
For example player.getAttributeValue(Registry.ATTRIBUTE.getId("generic.scale")

commented

Unfortunately attributes are limited to living entities, while scales are applicable to every entity, living or otherwise.

commented

It sounds like a nice idea, but in reality it scales rather poorly.
Maintaining additional release variants is costly.

Maybe I'll use the reflection based solution mentioned by @Virtuoel . BTW @Virtuoel does this work in a release environment (after remapping jars)?

commented

Just a thought that popped up in my head, not exactly sure if it counts for your goal of not needing a dependency in mind, but something you could theoretically do, should that code not work out right, is release an extension mod for Better Combat that uses Pehkui scales.

An example would be here with Create Support for Open Parties and Claims; a mod separate from 'Open Parties and Claims' that uses Create as a dependency so that the main mod doesn't need Create as a dependency.

commented

I've run it in both dev and prod, and since the strings passed to the reflection don't reference vanilla classes, only Pehkui ones, it does work outside the dev enviroment, yes.
(note that Pehkui 3.4.0 is currently buggy, so I recommend doing any testing with 3.3.3, or with 3.4.1 once I get to releasing that this weekend.)

commented
public static float getScale(Entity entity, Identifier scaleId)
{
	return getScale(entity, scaleId, 1.0F);
}

What would be the scaledId argument?

commented

It'd be new Identifier("pehkui", <type>), with the path parameter being one of the scale type ID strings used here, from whichever property is best suited to affecting the attack range of your weapons. My guess would be entity_reach or block_reach, but it's up to you.