Jump to content

[1.7.10] Player hitbox and hit mechanics - how to change stuff


Recommended Posts

Posted

Images of what I want to achieve

 

 

GvdLLx5.jpg

6vs4X5f.png

 

 

Hi everyone, hopefully the image above clearly demonstrates what I need to do

 

I need to change the way the players hit mechanics work. specifically to change the position of the players punching box (when you hit F3 + B) it would be the small white cube inside the players large hitbox (at least I believe this small hitbox represents the players arm and is used for actual collision calculations?). The diagram above hopefully clearly shows what I need to do so that the players reach is calculated from a different position.

 

Also I also need to resize the players hitbox to be smaller or larger (when you hit F3 +B) the large hitbox that appears I would need to scale that. The reason being is I have a very large model that the player can become. However, this model will only permit the player to play in 3rd person view. To make it look and work properly I need to have the position of the + cursor to be farther away from the model and represent the players reach distance. When you are my large model your reach distance should be a lot greater, but due to its size you should have movement penalty n not be able to fit into all places.  hence why I need to change the players hit mechanics and the players hitbox size.

 

I think some people have kinda dabbled into this a little bit, my goal is to get a fully working solution to this. I do know it is a tough problem though hence any input is appreciated.

Posted

It is known that changing player hitbox is fairly hard.

It might be easily done by changing some fields in EntityPlayer, which result in 'Player kicked by flying', so if you want that you have to allow flying to the player, and make your own way to detect flying.

Another way is changing rendering, hitbox mechanism, and click position adjustment independently, which needs a lot of works and potential incompatibilities with many mods.

So what way do you want to use?

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Posted

For changing reach, I would refer to Balkon's Weapon Mod source. In particular this event handling: https://github.com/Ckathode/balkons-weaponmod/blob/e223e96333734dcaff737a05482f5ce3b6eee968/src/main/java/ckathode/weaponmod/WMClientEventHandler.java

 

Basically it looks like he creates a moving object position with a length of the reach, and if it hits something he calls the attack method.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Extending reach was on my todo list for some time (after I finish other stuff) and I'll be there soon. I always planned to look into BWM but looking at it now - could someone explain to me not how, but WHY calculating reach and making attack on client works with server?

 

What I mean - if doing whole thing in client event and just telling server to do it (attack) works, wouldn't that mean that you can write client mod that will extend your reach to e.g 10 blocks? Why does the server allow such reach-change if it goes from client?

 

EDIT: My guess is there is some auto-correcting thing where server allows values up to some point, because if there is not, the above would be true, and that is just ridiculus for me.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Extending reach was on my todo list for some time (after I finish other stuff) and I'll be there soon. I always planned to look into BWM but looking at it now - could someone explain to me not how, but WHY calculating reach and making attack on client works with server?

 

What I mean - if doing whole thing in client event and just telling server to do it (attack) works, wouldn't that mean that you can write client mod that will extend your reach to e.g 10 blocks? Why does the server allow such reach-change if it goes from client?

 

EDIT: My guess is there is some auto-correcting thing where server allows values up to some point, because if there is not, the above would be true, and that is just ridiculus for me.

 

I'm not doing it in a "client event", but rather PlayerTick which I believe runs on both sides?

 

I've only tested it on integrated server single player, so I'll try it on separate server to see if there are issues. And the attack is run through the FMLClientHandler which I suppose helps manage the sync. I'm not that familiar with that.

 

I haven't checked how far you can extend the reach, but the code basically uses ray trace so I think it would simply be limited by whatever that method can handle.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Also little note: you have little flaw/dead code in your tutorial:

IExtendedReach ieri;
            if (itemstack != null)
            {
                if (itemstack.getItem() instanceof IExtendedReach)
                {
                    ieri = (IExtendedReach) itemstack.getItem();
                } else if (itemstack.getItem() instanceof IExtendedReach)
                {
                    ieri = (IExtendedReach) itemstack.getItem();
                } else
                {
                    ieri = null;
                }

Both else if and else is totally useless.

 

As to problem:

What I am certain of is that BWM is running this on CLIENT only - yet it works on server.

 

I'll also probably look into code. And for now - maybe someone else knows :)

1.7.10 is no longer supported by forge, you are on your own.

Posted

Ya Ive seen that reach code before, havent played around with his solution yet though. I wish the players hitbox/camera/reach n hit mechanics were more easily accessible using a forge hook or something like that. Ill try out some stuff before reposting, so far all I have figured out is how to change the camera zoom (but not its x y z position) not sure how to change the actual camera x y z position but I have been starting there. Once I figure that out then Im moving on to the reach, and the player hitbox. but all three are necessary to what I need to do. Otherwise, if the player uses a large model like a model giant third person is broken n useless and first person looks weird to other players since it looks like the hits come from my giants knees.

Posted

Both else if and else is totally useless.

 

As to problem:

What I am certain of is that BWM is running this on CLIENT only - yet it works on server.

 

I'll also probably look into code. And for now - maybe someone else knows :)

Yeah, I noticed the dead code myself today -- result of simplifying a previously more complex if-else-if construct.

 

I'm not sure what you mean by "BWM"?

 

But player tick runs on both, right? I put console statements in and see it running on both...

 

I have been looking through the EntityRenderer code for getMouseOver() and it does limit the reach (it calls "extended reach" by checking creative mode is on).

 

I think the flaw in my current code is that ray trace actually doesn't return an entity, so isn't doing anything. To get entity I believe is why getMouseOver() goes through a bunch of trouble to create a bounding box around the vector and checking for entities with and such.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Okay, I looked at it some more. The following code can definitely detect entities at a distance on both client and server:

 

@SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)

public void onEvent(PlayerTickEvent event)

{

if (event.phase == TickEvent.Phase.END) // only proceed if START phase otherwise, will execute twice per tick

{

if (event.player != null && event.player.swingProgressInt == 1) // Just swung

{

// DEBUG

System.out.println("Swinging weapon");

ItemStack itemstack = event.player.getCurrentEquippedItem();

IExtendedReach ieri;

if (itemstack != null)

{

if (itemstack.getItem() instanceof IExtendedReach)

{

// DEBUG

System.out.println("Using an extended reach item");

ieri = (IExtendedReach) itemstack.getItem();

} else

{

ieri = null;

}

 

if (ieri != null)

{

float reach = ieri.getReach();

// DEBUG

System.out.println("With reach = "+reach);

MovingObjectPosition mov = getMouseOverOrig(reach); // FMLClientHandler.instance().getClient().getRenderViewEntity().rayTrace(reach, 0); // getMouseOver(0, reach);

 

if (mov != null)

{

if (mov.entityHit != null && mov.entityHit.hurtResistantTime == 0)

{

// DEBUG

System.out.println("entityHit = "+mov.entityHit);

if (mov.entityHit != event.player )

{

// DEBUG

System.out.println("Attacking entity with extended reach");

// event.player.attackEntityAsMob(mov.entityHit);

// mov.entityHit.attackEntityFrom(DamageSource.causePlayerDamage(event.player), 4.0F);

FMLClientHandler.instance().getClient().playerController.attackEntity(event.player, mov.entityHit);

}

else

{

// DEBUG

System.out.println("entityHit is the player");

}

}

else

{

// DEBUG

System.out.println("entityHit is null");

}

}

else

{

// DEBUG

System.out.println("No MovingObjectPosition found");

}

}

}

}

}

}

 

public static MovingObjectPosition getMouseOverOrig(float dist)

{

Minecraft mc = FMLClientHandler.instance().getClient();

Entity theRenderViewEntity = mc.getRenderViewEntity();

AxisAlignedBB theViewBoundingBox = new AxisAlignedBB(

theRenderViewEntity.posX-0.5D,

theRenderViewEntity.posY-0.0D,

theRenderViewEntity.posZ-0.5D,

theRenderViewEntity.posX+0.5D,

theRenderViewEntity.posY+1.5D,

theRenderViewEntity.posZ+0.5D

);

MovingObjectPosition returnMOP = null;

if (theRenderViewEntity != null)

{

if (mc.theWorld != null)

{

double var2 = dist;

returnMOP = theRenderViewEntity.rayTrace(var2, 0);

double calcdist = var2;

Vec3 pos = theRenderViewEntity.getPositionEyes(0);

var2 = calcdist;

if (returnMOP != null)

{

calcdist = returnMOP.hitVec.distanceTo(pos);

}

 

Vec3 lookvec = theRenderViewEntity.getLook(0);

Vec3 var8 = pos.addVector(lookvec.xCoord * var2, lookvec.yCoord * var2, lookvec.zCoord * var2);

Entity pointedEntity = null;

float var9 = 1.0F;

@SuppressWarnings("unchecked")

List<Entity> list = mc.theWorld.getEntitiesWithinAABBExcludingEntity(theRenderViewEntity, theViewBoundingBox.addCoord(lookvec.xCoord * var2, lookvec.yCoord * var2, lookvec.zCoord * var2).expand(var9, var9, var9));

double d = calcdist;

 

for (Entity entity : list)

{

if (entity.canBeCollidedWith())

{

float bordersize = entity.getCollisionBorderSize();

AxisAlignedBB aabb = new AxisAlignedBB(entity.posX-entity.width/2, entity.posY, entity.posZ-entity.width/2, entity.posX+entity.width/2, entity.posY+entity.height, entity.posZ+entity.width/2);

aabb.expand(bordersize, bordersize, bordersize);

MovingObjectPosition mop0 = aabb.calculateIntercept(pos, var8);

 

if (aabb.isVecInside(pos))

{

if (0.0D < d || d == 0.0D)

{

pointedEntity = entity;

d = 0.0D;

}

} else if (mop0 != null)

{

double d1 = pos.distanceTo(mop0.hitVec);

 

if (d1 < d || d == 0.0D)

{

pointedEntity = entity;

d = d1;

}

}

}

}

 

if (pointedEntity != null && (d < calcdist || returnMOP == null))

{

returnMOP = new MovingObjectPosition(pointedEntity);

}

}

}

return returnMOP;

}

 

 

 

I have console statements in the code and if I run it and try to hit an entity 20 blocks away (I set reach to 20 in the item I'm using) multiple times the console shows:

 

[15:06:23] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:23] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:23] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:23] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.49, z=95.84]

[15:06:23] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

[15:06:23] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:23] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:23] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:23] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.37, z=95.84]

[15:06:23] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

[15:06:26] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:26] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:26] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:26] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.19, z=95.84]

[15:06:26] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

[15:06:26] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:26] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:26] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:26] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.19, z=95.84]

[15:06:26] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

[15:06:29] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:29] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:29] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:29] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.53, z=95.78]

[15:06:29] [Client thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

[15:06:29] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:166]: Swinging weapon

[15:06:29] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:174]: Using an extended reach item

[15:06:29] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:185]: With reach = 20.0

[15:06:29] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:193]: entityHit = EntityPig['Pig'/36, l='MpServer', x=-98.75, y=62.53, z=95.78]

[15:06:29] [server thread/INFO] [sTDOUT]: [com.blogspot.jabelarminecraft.blocksmith.FMLEventHandler:onEvent:197]: Attacking entity with extended reach

 

 

You can see that both client and server identify the pig. When I click elsewhere it shows null, and if I click on other pigs it shows different ID.

 

However, the attack doesn't seem to be actually processed. You can see I tried the attack in different ways (look at the commented out versions). I followed the code for each method and can't find anywhere it is specifcally deciding not to do the full attack.

 

Interestingly, if I use mov.entityHit.setDead(); I can instant kill the pigs from a distance, but even if I do a !worldObj.isRemote check (to confirm only server side), the kill isn't persistent -- if I save then load the pig reappears. Why would that happen?

 

So if anyone can tell me what the proper attack method to call would be, it should all work. I guess I'll try using custom packet.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Why are you using FMLClientHandler.instance().getClient() instead of just Minecraft.getMinecraft() ? They both return the client-side only Minecraft class (the docs say 'server instance', but that makes no sense when the class is client-only), and your code will crash on the dedicated server (unless there is some cpw magic going on that let's his code do what no one else's can).

 

There's nothing wrong, imo, with calculating the distance on the client side and calling PlayerControllerMP#attackEntity - this causes a packet to be sent and the attack will process on the server perfectly fine (though I haven't tested it with altered reach).

 

Alternatively, you can check out the Item#getMovingObjectPositionFromPlayer code which works on either side, alter it a little for your reach distance, and use that to find the object hit and go from there.

Posted

Why are you using FMLClientHandler.instance().getClient() instead of just Minecraft.getMinecraft() ? They both return the client-side only Minecraft class (the docs say 'server instance', but that makes no sense when the class is client-only), and your code will crash on the dedicated server (unless there is some cpw magic going on that let's his code do what no one else's can).

 

There's nothing wrong, imo, with calculating the distance on the client side and calling PlayerControllerMP#attackEntity - this causes a packet to be sent and the attack will process on the server perfectly fine (though I haven't tested it with altered reach).

 

Alternatively, you can check out the Item#getMovingObjectPositionFromPlayer code which works on either side, alter it a little for your reach distance, and use that to find the object hit and go from there.

 

I'm using FMLClientHandler.getClient() because that is what the vanilla EntityRenderer getMouseOver() code uses which I essentially copied. I actually tried Minecraft.getMinecraft() and other variations as well.  Also tried a lot of variations on the attack. Tried player attack with item, entity attack as mob, target entity attack from, etc.

 

The interesting thing is that I'm getting the entity fine, so the moving object position isn't the problem. But the attack doesn't process. Then like I said, just to confirm that something could be done I tried setDead() and it does kill (well makes it disappear without any drops) the entity from a distance.

 

Conceptually, I think it should work: I should be able to only process on client side and then send attack packet. However, as Ernio says, that seems like it potentially would be a hacking opportunity so it seems reasonable that the server might override any attacks that fall outside normal distance.

 

I'm sure it is something simple.  I think I'm going to add a custom entity so I can do more tracing of what is happening.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

You need to use PlayerControllerMP#attackEntity - this is what vanilla code does on the client when you left click, and it sends an attack packet.

 

EntityRenderer and objectMouseOver are all also client-side only, which is why I brought that up earlier - you are running single player with the integrated server, which has access to client only code because it is (was) part of the client jar. Just because it works in single player 'on the server' does not mean it really works like you would expect - your code will most certainly crash on the dedicated server.

 

When you call entity#setDead, you are on the client, so you 'kill' the visible version of the entity for you, but the server and any other players will still see it just fine.

 

Anyway, yes, allowing the target to be determined on the client side (which is what vanilla does) could open up to hacking, but only if you write your server-side packet handling poorly; you should be validating on the server that the player can actually reach (like vanilla does) and calculating damage and everything else independently of the client - all the client does is say 'hey, the player is trying to attack entity X'.

 

PlayerControllerMP#attackEntity is called on the client and triggers an attack on the server via a vanilla packet, and that is what I have used in much of my code because I am not messing with reach; to change the reach, you will probably need to send your own attack packet, but I highly suggest looking at the vanilla code first - you may be able to use it as is, and if not, it at least gives you a solid template for what you need to have in your own version of the attack packet.

Posted

I understand what you're saying, but there is still something weird (or at least that I don't understand).

 

I understand your point about some classes that are client side only being available in integrated server but crashing on dedicated server. But like you said my original intention was to process the mouse over on client side and use the built in attack packet to tell server. That fails though and I suspect it is due to something verifying whether it is a valid attack -- although I traced the code for a ways and couldn't see where (in the built-in mouseOver method it clearly limits the reach though, but I don't think that would be called again).

 

I think that the FMLClientHandler.instance().getClient() doesn't crash the server side so I think that is where some of my confusion was coming from -- I think it actually was running the server code on the client world!, which I guess is possible in integrated server?

 

Okay, I returned to the original idea -- run player tick on isRemote only and use the player controller attack method to send the vanilla attack packet. Here is my code:

 

 

@SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)

public void onEvent(PlayerTickEvent event)

{

if (event.phase == TickEvent.Phase.END && event.player.worldObj.isRemote) // only proceed if START phase otherwise, will execute twice per tick

{

if (event.player != null && event.player.swingProgressInt == 1) // Just swung

{

// DEBUG

System.out.println("Swinging weapon");

ItemStack itemstack = event.player.getCurrentEquippedItem();

IExtendedReach ieri;

if (itemstack != null)

{

if (itemstack.getItem() instanceof IExtendedReach)

{

// DEBUG

System.out.println("Using an extended reach item");

ieri = (IExtendedReach) itemstack.getItem();

} else

{

ieri = null;

}

 

if (ieri != null)

{

float reach = ieri.getReach();

// DEBUG

System.out.println("With reach = "+reach);

MovingObjectPosition mov = getMouseOverExtended(reach); // FMLClientHandler.instance().getClient().getRenderViewEntity().rayTrace(reach, 0); // getMouseOver(0, reach);

 

if (mov != null)

{

if (mov.entityHit != null && mov.entityHit.hurtResistantTime == 0)

{

// DEBUG

System.out.println("entityHit = "+mov.entityHit);

if (mov.entityHit != event.player )

{

// DEBUG

System.out.println("Attacking entity with extended reach");

// event.player.setPosition(mov.entityHit.posX, mov.entityHit.posY, mov.entityHit.posZ);

// event.player.attackTargetEntityWithCurrentItem(mov.entityHit);

// ((EntityLivingBase)mov.entityHit).setHealth(((EntityLivingBase)mov.entityHit).getHealth()-4.0F);

// mov.entityHit.attackEntityFrom(DamageSource.causePlayerDamage(event.player), 4.0F);

FMLClientHandler.instance().getClient().playerController.attackEntity(event.player, mov.entityHit);

// mov.entityHit.setDead();

}

else

{

// DEBUG

System.out.println("entityHit is the player");

}

}

else

{

// DEBUG

System.out.println("entityHit is null");

}

}

else

{

// DEBUG

System.out.println("No MovingObjectPosition found");

}

}

}

}

}

 

 

The MovingObjectPosition works because the console statements show the detection of the entity (or not) and also the entity will do a hurt animation (turn red and kick its legs) when hit.

 

However, the attack is only processed client side which is obvious since the entity doesn't die but I also created a test entity and put a console statement in the attackEntityFrom() method and that is only getting called client side.

 

So the packet never seems to initiate an attack on server side...I'm going to trace that code, and also probably try making a custom packet.

 

I'm glad you're responding though -- maybe try it out yourself if you're inclined. I'm sure it is something simple.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Okay, it does look like the entity attack packet processing limits the distance (to 6), here's the code:

   public void processUseEntity(C02PacketUseEntity p_147340_1_)
    {
        WorldServer worldserver = this.serverController.worldServerForDimension(this.playerEntity.dimension);
        Entity entity = p_147340_1_.func_149564_a(worldserver);
        this.playerEntity.func_143004_u();

        if (entity != null)
        {
            boolean flag = this.playerEntity.canEntityBeSeen(entity);
            double d0 = 36.0D;

            if (!flag)
            {
                d0 = 9.0D;
            }

            if (this.playerEntity.getDistanceSqToEntity(entity) < d0)
            {
                if (p_147340_1_.func_149565_c() == C02PacketUseEntity.Action.INTERACT)
                {
                    this.playerEntity.interactWith(entity);
                }
                else if (p_147340_1_.func_149565_c() == C02PacketUseEntity.Action.ATTACK)
                {
                    if (entity instanceof EntityItem || entity instanceof EntityXPOrb || entity instanceof EntityArrow || entity == this.playerEntity)
                    {
                        this.kickPlayerFromServer("Attempting to attack an invalid entity");
                        this.serverController.logWarning("Player " + this.playerEntity.getCommandSenderName() + " tried to attack an invalid entity");
                        return;
                    }

                    this.playerEntity.attackTargetEntityWithCurrentItem(entity);
                }
            }
        }
    }

 

You can see that the distance squared needs to be less than or equal to 36 if you can see the entity.

 

Okay, going to make a custom packet.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

I'm not sure what you mean by "BWM"?

Balkon's Weapon Mod.

 

Just to note out: I've never actually tested this stuff ouside of what is done by BWM.

This code:

https://github.com/Ckathode/balkons-weaponmod/blob/e223e96333734dcaff737a05482f5ce3b6eee968/src/main/java/ckathode/weaponmod/WMClientEventHandler.java

Very clearly IS ClientEvent (even class name says so), that's why I wrote "What I am certain of is that BWM is running this on CLIENT only".

 

And yeah, I found the code responsible:

PlayerControllerMP#attackEntity sends C02PacketUseEntity which is then processed on server:

        if (entity != null)
        {
            boolean flag = this.playerEntity.canEntityBeSeen(entity);
            double d0 = 36.0D;

            if (!flag)
            {
                d0 = 9.0D;
            }

            if (this.playerEntity.getDistanceSqToEntity(entity) < d0)
            {

 

So max reach is 3/6.0D.

Altering this any further would require you (someone) to either use ASM and override value, make new attackPacket as coolAlias sugested OR override whole NetHandlerPlayServer.class which would be shocking easy since it's Interface (overkill).

 

EDIT:

You were faster jabelar xD I don't know why I didn't get notification.

1.7.10 is no longer supported by forge, you are on your own.

Posted

Yep, that's what I was saying, but I couldn't recall exactly where it took place. The packet HAS to VERIFY that the action is valid on the server, thus the distance check when processing the vanilla attack packet. You will need to do the same in yours, or you could use ASM to modify the vanilla packet to include a hook for determining the player's reach distance, perhaps via your Item interface. Easier to make your own packet ;)

 

As for FMLClientHandler's getClient() method, I don't see how that is any different from Minecraft.getMinecraft() except for it takes longer to type. It will still crash you on a dedicated server, and shouldn't be used on the integrated server either, although the code will function if you do it on the latter.

 

The integrated server can technically run @SideOnly(Side.CLIENT) code because it is part of the 'client' environment, i.e. what used to be the single player .jar. This is why diesieben and other people always say not to use that annotation and try to stress that it has absolutely nothing to do with logical side - it is very misleadingly named, or rather its name overlaps the terminology used to describe other things.

 

EDIT: Looked through BWM's code and I'm not sure how they managed to get the reach to work - I can see that they use the vanilla PlayerControllerMP method which calls the vanilla packet, and this makes me suspect that perhaps their reach system doesn't really work the way they think it does. Or they may have patched it with ASM, or I just haven't found their code yet.

Posted

Okay, with custom packet it seems to work like a charm. I was sniping pigs from 30 blocks away with a "sword".

 

I'm going to bed now, but will update the tutorial tomorrow and maybe you can give it a review.

 

You're right I should prevent hacking by double-checking the range on the server side, as right now I basically created a "kill any entity" packet. Should be easy fix.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Okay, I checked it all with dedicated server and it works well. I've updated my tutorial -- I'd appreciate your reviews: http://jabelarminecraft.blogspot.com/p/minecraft-modding-extending-reach-of.html

 

I think this could be a good approach for a gun mod, rather than creating invisible projectiles. The targeting seems quite precise -- could pick off entities that were mostly hidden by blocks.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

The only major change I would make is to use the KeyInputEvent and/or MouseEvent to process directly when the player presses the attack key (left clicks), rather than adding yet another thing to process every single tick.

 

I would only use the tick event if you are trying to wait until the player's arm swing has reached a certain point, but I'm pretty sure vanilla doesn't bother to do that, and in your example code you process right when the player first swings anyway.

 

Another point is you can write an int directly with ByteBuf#writeInt; I don't know if you're trying to save a byte or two in your packet or whatever, but for a tutorial simpler is usually better - unless you want to explain to folks what the arguments are and why you chose '4' :P

 

I would also encourage you (and everyone else) to name variables something relevant, rather than var2, var9, etc., especially in a tutorial where you'll have lots of people that already have a harder time understanding code trying to figure out what you're doing.

 

You'll probably want to add comments within the code to help people out, too, and maybe break the code up into finer sections which are easier to explain rather than entire blocks of code - otherwise all you've made is copy-pasta for hungry folks who don't know how to cook, and they'll eat it without even checking the ingredients.

Posted

Thanks for the feedback.

 

Regarding the variable names, I have been going through the code to rename them but it is copied mostly from the vanilla getMouseOver and frankly a few of the things it is doing aren't quite clear to me. But yeah, I'll make it more readable if I can.

 

Regarding the ByteBufUtils, I like to let people know about that class because it helps with more complicated messages including NBT and stuff. But I'll explain it better.

 

Moving to the input event is good idea. I started with the other mod's code and they had it in player tick so I didn't think to move it, but it makes sense.

 

Thanks again, as always!

 

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.