#Damage Events
1 messages · Page 3 of 1
so you'd be asking to get rid of LivingIncomingDamageEvent
and keep the shield event
which is then gonna confuse the shit out of people
unless you then rename the shield event, which will then again confuse people looking to do shield stuff
Is this a reason or a useful side effect? Ironically, inner classes would also make it convenient for searching
yeah so here's the problem
and the reason I wanted the names changed
the average user, who uses these events
do not search or look through event heirarchy
those are your common idiot (AkA newbie dev)
then you also have the people who may or may not have experience and are just looking for an event to use
these events are some of the most widely used events in the entire API
and requiring users to 'just know' you're meant to look at the heirarchy and whatever to work out which one to use
will not happen
full stop
it just won't
the event name itself has to be its own descriptor
and we know thta to be true because we've seen this circumstance happen so goddamn often already
So you are basing the PR off of the idea that we should not inconvenience low information users (who could gain information by reading the event file)
If it is so prevalent, I suppose its worth shelving that whole issue just to assuage the collective annoyance brought out by that
low information users & those who are just looking for something to use
this may come as a shock to you
but not everyone looks at the entire event heirarchy every time they want ot use an event
I don't appreciate the tone
this is me looking at the issue from what I am assuming is your point of view
I am frustrated by the seeming complete lack of awareness of the already existing issue that we're trying to resolve
I assumed the continued annoyance and made the conclusion that I would, in that mindspace, agree with you
another way to look at this is to consider the bar of entry being lower means more modders who stick around to learn the intricacies instead of abandoning the API altogether. there's an arguable benefit to the project to lower arbitrary bars
I mean the perceived higher bar to entry is one of the most common arguments people use to push people to fabric
I think you are misinterpreting my words, but I have also seen you use this tone for the preceding conversation
it's very clearly beneficial
so, it was not just me
I don't think its productive to be like this, personally. Maybe it is, though. I am not well-versed in these sort of developments, so I could be off the mark.
how about this. what if we create clear definitions about what each event's purpose is then if we agree upon that definition we can use that as a basis for a name?
that's the problem
shadow's argument seems less oriented about what the event is used for
and more about how the API reflects its position in the chain
I fundamentally disagree with that approach
then we hybridize those perspectives in our definition. we may end up with a chimeric name, but it will ideally meet all needs
I don't believe it will, but I'm open to the attempt
I can edit this if you think I need to
I think at the very least changing to this would be a good improvement over the current names
#1198800008225501285 message
is this about the shield event? I realize that I have brought up two different topics here so this is my fault, but I am unsure of where we ended up in regards to the current topic
this is about the entire thing
the shield event is just one small almost entirely unrelated tangent shadows went on
I think specifically shadow is right about the shield event
shadow has a point about it
but it opens up other issues if you go with his solution
as I explained above
the shield event currently does more than the incoming event
so you'd have to get rid of the incoming event
if you do that, then people who just want to cancel the event are going to be confused trying to figure out wtf they're meant to do
even in searching cus it'll just look like they're using a shield or something
if you then change the name to account for that, then people looking to do stuff with shields will be lost
Event 1 (LivingEntity#Hurt after the invulnerability checks)
The point at which a vulnerable living entity is provided a damage type and value from the attacker's successful attack wherein listeners can modify this damage value.
I don't disagree that they have similar usages, but I don't think similar means the same, and having an event specifically used for recording incoming attacks or outright cancelling them (as opposed to blocking them, which is functionally distinct)
is worthwhile
Why would the incoming event need to be removed if we agree to limit the scope that the vanilla shield event is used for? Is this something I have to review the code to understand? OR is this an implication that follows from how Shadow talked about the issue?
wait why are we arbitrarily limiting an event?
that seems incredibly counterproductive
arbitrarily? I am reducing it from general damage blocking to purely just modification of vanilla's built in shield blocking.
that's already what it's for
it just also allows you to dynamically modify the amount of damage a shield blocks
which is a heavily requested feature
given that vanilla shields are incredibly limited in scope
that's important because the amount of damage a shield blocks also usually correlates with the damage a shield takes (durability)
so you can't just push damage reduction to a later event
and we shouldn't be encouraging people to modify damage in a prior event
Specifically, I interpreted the following as this being considered part of the shield blocking event's scope and thought that it was tangential to it.
it's a side effect of it
the main goal is to allow for non-vanilla shields that can do different things
but as a side effect it also allows for people to do non-"shield" stuff too
which you can't really limit without defeating the benefits of the event in the first place
and I don't see why we should tbh
having the shield and predamage as separate events creates a separation of purpose. predamage is for cancelling, and changing the initial value. block event assumes that first modification is handled and that the damage coming in is intended to be used as is. You can imagine if there were 5 listeners to predamage that were a mix of damage amplifiers and shield-based damage nullifiers, you'd have conflicts of priority. but if the shields wait for the shield event, then it's clear that your damage modification is contextually in the correct place.
i used shield for Block because i had mana shield as my mental example
I don't even think of mana shields tbh as a primary
like right now vanilla shields are broken OP
I know modders that want to be able to do modded shields that aren't just 'they hit back' or whatever
so being able to modify the actual blocking values and stuff is very valuable
they don't have to be. i was just thinking of something that the old event wouldn't capture because of the vanilla isBlocking checks
I don't disagree with that. Hypothetically, if something was to be shield-like, it should borrow vanilla shield blocking and use the shield event to extend the functionality
that's.. what this PR does
that's the whole point of that event
lol
that's quite literally what the change to the event was all about
but the other event is still there to just be a 'I need to cancel this attack before it happens'
I believe that the way I communicate is definitely confusing the topic here, sorry
or if for some very specific reason you needed to modify the initial damage input, but is discouraged as a general thing
I was following up with my own realization of why you held your current stance on the event
tan estrano
anyway shadows' thing was about changing the name(s)
but his focus is more on the events as a collective chain
which I can understand but fundamentally disagree with
because users don't care if it's in a chain
he also had that thing on the PR about carrying invulnerability or something into the invuln event
which I'm not entirely sure I understand
The sequence is not the most important aspect of the events, I can agree on that part
I don't either, which i'm still waiting for an explanation
What are the important things about Pre that we may infer from the sequence, but are not readily apparent to lower information api users?
that could help with naming it
i'm for Tslat's suggestion
EntityInvulnerabilityCheckEvent
LivingIncomingDamageEvent
LivingBlockDamageEvent
LivingModifyDamageEvent
LivingDamageTakenEvent
it's for incoming damage
that's.. as broad as you can get
it is also "pre" damage, but that infers a correlative ordering, which is what caused this in the first place
but you can't really narrow it down to more than that, cus then it limits its potential scope
I have returned; let me go read all of this...
#1198800008225501285 message
what if we used the above names. but still nested them in the parent class as sub-classes so that the API has a sense of sequence, but the names themselves are user-friendly?
I'm not really bothered how the events are laid out internally tbh, my main focus is on fixing the problem they already have
which can only be fixed with the names themselves
so if that's an acceptable solution then I'm fine with that
😅 anyone know how to sub-class refactor in intellij?
just wait
better to decide on a solution before implementing every possible one lol
oh for sure. i just remember not finding the feature when i unsubclassed the internal damage container and know these ahve a lot of references i'd like not to update manually
I get his response to this now
I think a rename might be the best approach
I think my problem with IncomingDamage is that its meaning relies on knowing the name of the other events, especially DamageTaken
DamagePotential? ugh idk
an outright removal feels like an unnecessary loss of valuable information when it'd only be affected by some edge cases
oh? rename on what?
and a mod could override and account for that if they so wanted
how so
isVanillaInvulnerable
actually
no
I still don't agree
its not clear that IncomingDamage can be damage that never happens unless you also know that DamageTaken exists
because even if an overriding caller is handling this
it'll only get to this call if the parent call fails
so the vanillainvuln value will still be correct and relevant
it'll just not be overriding, but that can only be fixed by handling all call sites
which is not a great idea obviously lol
and only happens in 3 places, which aren't wholesale upsets of the design
Tslat: so you'd be asking to get rid of LivingIncomingDamageEvent
[1:34 PM]Tslat: and keep the shield event
I would say keep both and restrict the shield event to just shields. Currently blocking something with the "block" event will transiently ripple into calling shield-specific code paths, even if a shield is not present.
You could rectify this, but then you need a complex patch and extra flags to say if the damage was blocked by a shield or not.
Tslat: the event name itself has to be its own descriptor
This isn't necessarily correct, but the names have to not be ambiguous at face value (which the current pre-PR names are). The ambiguity makes it harder to recall what the purpose of the event is between the similar names.
there's an arguable benefit to the project to lower arbitrary bars
Agreed
how about this. what if we create clear definitions about what each event's purpose is then if we agree upon that definition we can use that as a basis for a name?
This is a reasonable approach to determining the name surface, though I think it was tabled earlier.
having the shield and predamage as separate events creates a separation of purpose. predamage is for cancelling, and changing the initial value. block event assumes that first modification is handled and that the damage coming in is intended to be used as is.
It's difficult to define that an event firing right after another event really separates anything. Though refer to the earlier blob about side effects of expanding the shield event.
I would say keep both and restrict the shield event to just shields. Currently blocking something with the "block" event will transiently ripple into calling shield-specific code paths, even if a shield is not present.
You could rectify this, but then you need a complex patch and extra flags to say if the damage was blocked by a shield or not.
I too love arbitrarily reducing functionality because you don't like the name of a class
The shield thing isn't about the name
add a boolean to the event to skip the blockwithshield call if you want
I do'nt see why we should fuck over everyone who wants to use this event properly because we didn't want to add a boolean
Because I don't have to maintain a bunch of patches to the vanilla shield logic t.t
it's all in one place
except for the one external patch to wrap the vanilla handling
at which point your argument is we should just not have the event
because it's work
For example, if the player enters a rage mode after taking damage, and I search for an event to do this and find and use IncomingDamage, then I can enter a rage mode even after I block damage by some means. I would have to see all the damage events side by side to understand the extra meaning attached to incoming.
I think calling it DamagePotential (or similar) would clue users into the idea that the damage from this event may not even happen.
yeah this is why it was originally called Pre
to denote that it was before anything happens
but that caused a problem for shadows
Because we conventionally use Pre only to describe a linked series of events
I understand
I'm just explaining
I'd rather get rid of pre than change damagetaken to post
I also don't think Pre conveys that directly, but just by one level of connected meaning
This is what I would setup for the first two
LivingAttackedEventas the first one. Fires where pre does now with all the control pre has now. Name conveys a target has been attacked by a damage source.ShieldBlockEvent(revert the changes and reduce the scope back down). Other non-shield damage reductions can happen in the former event.
They've been attacked; the reason people got confused with LivingAttackEvent was that it sounds outgoing (i.e. when a mob attacks someone else on the attacker side)
but its on the receiver side
might wanna put a marker in Neo that we're not allowed to work on shields again in the future then
if we can't have it now, mightaswell blackmark the whole section for future work
(Since obviously (to us) you have to cancel the first event (which we know pre to be) to limit the number of side effects)
Shadow made a good point about how the recipient of the damage might be confusing from just reading the event name
Incoming solved that in a way that my just-proposed alternative didn't
IncomingPotentialDamage 😭
Incoming is also fine as a name for the first thing
wait so what's the problem with the current proposed name then? LivingIncomingDamageEvent
Its fine, it's just not what i would pick given the context
For the final two events
which seem more contentious
so either LivingIncomingDamageEvent or LivingIncomingAttackEvent
^
the reason I didn't want Attack anymore
is because damage doesn't have to do with attacking anything
they could've just walked into a cactus
Damage is more accurate
that its not an inevitability, and that you could only realize that this is the case if you compared the naming of the other damage events too
we would want to go with LivingDamageEvent.Pre/Post. But to do in a "sensible" fashion requires removing Damage from the other ones for sanity (hence a push for Attack)
Alternatively it can just be LivingHurtEvent.Pre/Post, which is fine, given the call site is atomic in actuallyHurt
no thanks
I realize tslat hates the word post
I hate Pre/Post
But that is the pattern we use for this project
I'll literally harbour anger at you over it if it goes through
it is an absolute decimation of the first point of this PR
Consistency across the project is more important than any individual's feelings towards the paradigm
the consistency implied here is entirely arbitrary
I would say keep both and restrict the shield event to just shields. Currently blocking something with the "block" event will transiently ripple into calling shield-specific code paths, even if a shield is not present.
You could rectify this, but then you need a complex patch and extra flags to say if the damage was blocked by a shield or not.
Nothing in vanilla logic necessitates the item in hand be a shield. it actually exits the whole logic if the item doesn't have a shield block action type.
having the block event as in the PR now with the expanded scope adds a place for extended functionality (and in a place suited for it). LivingDamageBlockingEvent? so that it's more active about being an active action?
strip out the superclass and it's not even relevant anymore
any individual's feelings towards the paradigm
mate I have bot commands in both major community modding discords
because of how goddamn often this shit caused problems
it's not a "me" thing
it's a "people already get this wrong and I want to fix this" thing
That's unrelated to naming new things pre or post
I think Pre and Post are a great standard for events but I didn't really want to push my luck with that here atm
Shadow what do you think about this suggestion? #1198800008225501285 message
The final two events are fired in tandem in actuallyHurt in accordance with the precident for Pre/Post events. One always fires before another, and only the former is mutable
Tslat, I get your point, but please, comments like this are not contributing anything
they are
i'm for moving DamageTakenEvent to inside the condition. that makes sense.
It's better than the current approach for linking, yeah
shadows is trying to be reductive about my opinion
implying it's a "me" thing
it is not
firing that event when damage is zero doesn't make sense.
Tslat has argued the processes are not linked, though. I believe he's right on that action for the former and the latter pairs
Which is why pre as the first and post as the fourth don't work
okay, let me rephrase this
The first two are even only tangentially related due to how you want to separate the purpose there
the way you are reacting to it is not contributing anything
The latter two are explicitly related
ok I'll include more emojis
my response was entirely valid and relevant
yes it was, I'm talking about the tone
#3 fires with mutable context of the post-reduction damage before application, and #4 fires after application of damage
what if we IncomingDamageEvent and DamageTakenEvent were changed to LivingDamageTakenEvent.Pre/Post ? this conveys one is before the damage is taken and one is after in a way that is consistent with the rest of the API
we are all working on the same project, and we're all doing this in our free time
Its a tad verbose, but it works well enough
this is Java lol. verbosity is king
I say that because I think you can get the info without Taken, but it doesn't really matter
and some of us have been trying to resolve this issue for literal years only to be told that it's a "me" issue
I'd like you to remember that, because I feel like you're not really considering Shadows' points here
I'm sorry if I'm mildly invested
You are not wrong, but Shadows isn't either.
I'm considering shadow's points just fine
Taken adds clarity in ways that Tslat is advocating for. I think it's valuable to keep in
I'm not saying shadows is wrong
I'm saying he's fundamentally misunderstanding the problem we currently have and what this PR aims to resolve (among other things)
I think this is still going to cause the same confusion problem
If it satisfies the requirement amicably the verbosity is a fine cost. It won't really hurt anyone
Thus the set becomes:
#1 - LivingIncomingAttackEvent / LivingIncomingDamageEvent / LivingAttackEvent
#2 LivingShieldBlockEvent / LivingDamageBlockEvent
#3 LivingDamageTakenEvent.Pre
#4 LivingDamageTakenEvent.Post
it implies that the damage is already taken one way or another
and that it's not mutable
"Pre" events are generally accepted to have mutable control over the action that is about to occur
Shadows isn't trying to sabotage this, he's just voicing his concerns
sigh
I'd like you to recognize that, thank you
is #1 a list of suggested names? there's only one event before the block one
Yeah
So the pre is just before damage is applied and post is after damage was applied to the entity? If so, those names makes sense and I haven’t event looked at the pr or really follow this convo lol.
Same for #2 though the names are functionally controlling. I was going to do a brief assessment over the side effects of considering a blocking action is a shield
okay. is #2 the same or is this suggesting restoring the old shield event?
okay. i have to pack up to get off the train. please don't write novels in my absense lol
no deal, I'm already in talks with my publisher
Then please be a bit friendler. Comments like calling Shadows' messages "bot comments" is not friendly.
So... shields:
We have this hunk
if (!net.neoforged.neoforge.common.CommonHooks.onEntityPreDamage(this, this.damageContainer)) return false;
// ... local variable decls
net.neoforged.neoforge.event.entity.living.DamageBlockEvent ev;
if (p_21017_ > 0.0F && (ev = net.neoforged.neoforge.common.CommonHooks.onDamageBlock(this, this.damageContainer, this.isDamageSourceBlocked(p_21016_))).getBlocked()) {
this.damageContainer.setBlockedDamage(ev);
if(ev.shieldDamage() > 0) {
this.hurtCurrentlyUsedShield(ev.shieldDamage());
}
f1 = ev.getBlockedDamage();
p_21017_ = ev.getDamageContainer().getNewDamage();
if (!p_21016_.is(DamageTypeTags.IS_PROJECTILE) && p_21016_.getDirectEntity() instanceof LivingEntity livingentity) {
this.blockUsingShield(livingentity);
}
flag = p_21017_ <= 0;
}
I think ihh misread one of your statements
wait nvm I misread this
nvm me
But yeah. End of the day, I'd ask you to embrace the fact that Shadows is trying to improve this API just as much as you are, even if it might not be that obvious to you. Thank you.
If you wanted to perform general pre-anything reduction, event #1 suffices. If you want to trigger a shield-like blocking action, you have to use #2.
Triggering a shield-like blocking action without a shield may have unusual side effects relating to arrow piercing and game events
and again, I'm allowed to disagree lol
the aim of #1 is for cancelling, primarily
you can modify it if needed but it's meant to be discouraged
in favour of using the modifydamage one
If you want to consume pre-mitigation damage you would likely use #1
yeah
but with a lower priority
The existance of priorities imo makes expansion of the shield event not super necessary
We may want a hook that permits controlling the "shield area" for shield items
I disagree
having this here allows for far more control over shield usage
both vanilla and modded
making it reductive means you have to reimplement the whole algorithm yourself then potentially cancel/handle the other event too, etc
What whole algorithm? Calling isDamageSourceBlocked?
yes
it's a public method, you could call it from a handler for event #1
right but if I want to change how that works for a custom shield
I have to reimplement the whole thing just to change it slightly
as opposed to it just being present
That's something that should be in a hook for a shield item (maybe on IItemExtension)
right
except you might have a non-item based shield
such as a mana barrier or something
I don't have codebase available atm, do shield blocks trigger iframes?
Then we might want a better check in LivingEntity#isBlocking
Actually is that even called anywhere else?
everything triggers iframes except invuln & cancelling the first event
nope... just for some player head rotation code 
ah, so my following thought could be relevant
what if it's not your entity
which tends to be the case
such as players having a mana barrier...
I wonder how cancelling a damage event but triggering iframes would be best handled here. It feels like a commonly desired behavior...
atm id do this using shield block somehow with the given pr, so that might give extra credence to expanding the shield event
A mana barrier being a global (i.e. from all directions) "shield-like" blocking option?
if oyu're cancelling the damage then you don't want iframes
that's the point lol
if you want to block some of the damage, but not cancel it
then you use damageblocked
if you want to modify it for other purposes, there's the other event
I want to cancel all side effects of the damage aside from the ones that come from shield blocking
or directional, or just a gravity repulsor, etc
I.E. some form of custom "blocking" functionality that doesn't have to be an item
In this case I would still think you would want it to be named Shield... to convey that the "blocking" action triggers shield side effects.
I think general pre-mitigation reduction should still be in that first event, and shield-esque effects in #2
yeah i get this logic
which is why I proposed having that extra boolean
to skip out on the blockwithshield call
if the shield isn't item based or for any other reason
instead of hampering the entire event, allowing more configurability through a basic boolean seems ideal
i actually need to delve into what that does
it just does knockback
and does shield disabling for players
axe hit, etc.
I think vanilla has some overrides for like ravager doing stuns and stuff
but imo that's all stuff that should be configurable as part of the event
so if anything that just pushes me further into wanting a boolean
Well, right, if you have a non-shield-like block, just do damage reduction in #1
maybe "isPhysicalBlock" or something?
it's a separation of responsibilities lol
in general, modification of damage in #1 should be avoided and discouraged
otherwise it muddies things
functionally yes, but ideologically no
without shield side effects
not sure.. my imagined use case was dodging projectiles (with a cooldown) but also having iframes for erring on the player's side on the actual gameplay value of the dodge (so a burst of arrows doesn't just strip you of the cooldown and also hurt you)
eh you can do that either way
cancel in #1 then set iframes manually
part of the problem is that not cancelling the attack also does the hurtTime
so you get that red overlay and stuff
I agree
I guess more specifically, is this kind of thing common enough to address in any direct way with some helper?
I mean that's kinda what #1 was intended for
dynamic attack cancellation
dodging, etc.
The separation of uses (early cancel vs pre-mitigation reduction) for #1 is the job of event priorities
right but what if your barrier only works after shield block
oh specifically specifically cancelling damage and all side effects aside from iframes
but now I have no idea why I was asking that lol
like it's a skin-layer thing, or you just want the physical shield to take priority
Well then you kinda want it to be after #2 entirely
to account for other mod's shields
right except your lastHurtamount gets screwed
as does your helmet damage
and your hurt marking, etc.
all the crap that happens after shield but not inside actuallyhurt
the other shields was partly why I didn't want to do #1, but past #2 I think there are some side effects
weird design btw vanilla, wtf you doin
almost like you want it to be a part of #2
so that you can avoid both situations
weird
yeah! I mentioned this use case for that reason
maybe I needed to explain it more before this made sense
part of the issue here is vanilla's bizarre decision to decouple hurt and actuallyhurt, but put half of hurt's stuff past actuallyhurt with no backreference to it lol
I perfectly understand and agree with your thoughts on it shadows, but I just feel like there's enough of a niche there to warrant keeping the event expanded as-is
custom shield/blocking handling is pretty common
and relegating it to before the shield block is handled is.. fkin weird lol
In terms of "time" its at the same point
yeah it definitely looks like someone else came in to quickly patch some desired behavior (or to fix a bug) without fully refactoring. Justifiable but it does affect mod efforts lol
yeah but it handles different parts of the chain
like if we're already handling shield blocking stuff
why not keep the shield blocking stuff as.. part of that
as opposed to have some shield stuff here, some there
that just feels wrong
Its due to what vanilla has defined as a shield blocking action
If you want all that behavior, event #2 is fine
right but we're not vanilla, we expand on vanilla, including shields
and shield-like handling
maybe rephrase
Trying to mangle the logic and the patches to support shield-like and non-shield damage reduction at once isn't worth the complexity when you could just reduce in #1
what's your actual issue with the shield thing at present
is it the extra wrapping outside of hurt?
The issue at current is the suggestion that all pre-mitigation go through that event, when it triggers side effects specific to using a shield
Well then we could keep it with Shield in the name, no?
To say "this is shield and shield adjacent handling"
I mean I'd prefer not to, but I'm ok with it if that's your gripe
just to encourage people to stick to "shield-like" stuff I presume?
I'm ok with that
Yeah
👍
damage is my 100% preference
purely because damage incoming doesn't mean attack
environmental, etc.
Attack is... maybe more "unique" w.r.t. the final two but I guess you wouldn't be "attacked" by a cactus
The cactus jumped me
I get what you mean about naming it attack
but yeah just feels too far removed from what's correct
call it LivingHurtEvent, no confusion there 
they haven't been hurt yet
so.. technically not lol
hurt is both present and past tense which is ick
LivingMightBeHurtInTheFutureEvent™️
IncomingHarm
IncomingInjury
ThingsAreAboutToHurt
ItsHurtinTime
But yeah the only value in "Attack" is clear disambiguation from the final two
DamagingStartup
how valuable that is... idk
actively damaging when you consider damage isn't necessarily an attack lol
and the word "Incoming" may solve the issue
what about
LivingDamageEvent.Modify
LivingDamageEvent.?
I couldn't think of the post equivalent lol
I think we should just go with the pre/post there
-.-
Its well defined what those terms mean
users will be familiar with them
"happens before the thing with mutability"
"happens after the thing without mutability"
maybe from an API perspective lol
I can tell you that modders in the public don't implicitly understand that
LivingDamageSourceAndAmountReceivedAndAboutToBeProcessedEvent
if you don't have a specifically notable name
people will default back to IncomingDamageEvent
cus it feels more relevantly named
and we're back to where we were
#1 LivingIncomingDamageEvent
#2 LivingDamageBlockEvent
#3 LivingDamageTakenEvent.Pre
#4 LivingDamageTakenEvent.Post
(could redo #1 as LivingDamageIncomingEvent if we're being pedantic)
I still don't like pre/post and never will lol
we're gonna have another LivingHurtEvent situation and I'm gonna be annoyed eternally
I honestly hate the Incoming word here because that might just as well be the case at any other section of the chain
I'm not sure we will be able to avoid the confusion here, just because of how convoluted the entire system is to begin with
LivingAttackedEvent returns™️
Maybe you can't be attacked by a cactus in a pure english grammatical sense but eh
Attacked by the ocean™️
LivingHurtEvent then, due to the call chain starting at hurt
(yes I know this is bad)

It would be better if actuallyHurt wasn't called that
i think its best distinguished by potentially happening wheras other places its "certainly" happening
But it is 
I think LivingHurtEvent would make the most sense honestly, but I see why you wouldn't wanna do that due to, uh, historical reasons
I think historical reasons are important here tbh
people will just fix their import
and not change their historical usage
LivingPainEvent
I don't really agree with LivingHurtevent being correct either tbh
from an API perspective yes, but not from a usage perspective
which is the issue we currently have
1. LivingOuchyEvent 2. LivingHowBoutNoEvent 3. LivingOhYouMeantItEvent 4. LivingThisIsMyLifeNowEvent
- LivingIncomingDamageEvent
- ???
- LivingDamageTakenEvent.Pre
- LivingDamageTakenEvent.Post
#1198800008225501285 message
Shadows:
#1 LivingIncomingDamageEvent
#2 LivingShieldBlockEvent
#3 LivingDamageTakenEvent.Pre
#4 LivingDamageTakenEvent.Post
My issues with this - it adds ambiguity to #3/#4 that will cause users to just default to #1, and we're back to LivingHurtEvent all over again
Mine:
#1 LivingIncomingDamageEvent
#2 LivingShieldBlockEvent
#3 LivingModifyDamageEvent
#4 LivingDamageTakenEvent
Shadows issues with this - it doesn't conform to NeoForge's current api standard of doing pre->post for sequential events
I'm happy with a middleground of
#3 LivingDamageEvent.Modify
#4 LivingDamageEvent.?
my main goal is to avoid LivingHurtEvent v2
which I strongly feel pre/post will result in
LivingDamageEvent.Subclass1 and .Subclass2 is bad for anything that isn't Pre/Post
however pre/post is bad here too because we have more than 2 events in this chain
so I think pre/post is used rather arbitrarily here
shadows' logic is that 1/2 are functionally separate from 3/4
I'm not entirely sure I agree
but that's the logic anyway
that being said, I dislike the name LivingModifyDamageEvent
3/4 are called atomically in order from actuallyHurt
i.e. for 4 to ever occur 3 must occur
well that's not currently true tbf
this popped up more as a joke in my head, but LivingActuallyHurtEvent.Pre and Post?
but calt was looking t ochange that afaik
It is called actuallyHurt after all...
I'd prefer LivingDamageEvent.etc
but Pre/post is my main issue
it's not self-descriptive enough to drag users away from IncomingDamageEvent
I think doing LivingDamageEvent.Pre/Post is bad because the name LivingDamageEvent is too generic
It was LivingDamageTakenEvent.pre/post
even worse imo lol
LivingDamageTakenEvent.Pre makes no sense
past tense and Pre in the same event name is confusing
but yeah it sounds like you more or less understand what I'm trying to say
it makes sense from an API perspective, but historically this has been about a usage problem, not an API problem
and it'll continue being a problem to perpetuity unless we fix it here
I was thinking LivingApplyDamageEvent.Pre/Post, but that doesn't really solve the generic name problem
yeah, and I'm glad we agree that we should meet on middle grounds here
my issue is
I'm not sure what middleground there is
if Pre/Post is theo nly option for child event classes
not just yours, don't worry
Pre/Post is really only an option because it is successfully (and a lot more intuitively) used by other events
I think the past tense helps to convey that damage is going to be taken. sure you can set the value to zero, but all other damage effects have happened. The pre lets you know that you are in an early stage of this process and therefore have some ability to change the later state with post being the end marker
the fact that we have to think so hard for an alternative name to something that currently describes its usage almost perfectly feels like it should be a hint lol
the damage event sequence is everything but intuitive, so pre/post isn't really descriptive unless the wrapping event name is
yep
damage confirmed
the thing is, I don't believe that DamageModifyEvent is a descriptive name
tbf that wasn't my original name lol
it got changedo nly today cus of shadow wanting to change Pre
because quite frankly, DamageModifyEvent could be just about anywhere in the event sequence for all I (an unknowing modder) know
yeah but the sequence doesn't matter for damage
it's about the usage
you know that you use that event for modifying damage
it's immediately apparent that's what it's for
same, and it happens after reductions, so it's too late for most things. Which is also why i disagree that #1 is not a good target for modifying the damage. I'm with Shadows that a pre-mitigation damage modification is and should be an option at that stage
wait am confuse
we changed the event positioning because of the damagecontainer thing didn't we
my question then is, why should I use any other event than LivingDamageEvent
correct
one sec
(except for DamageTakenEvent which is obviously called afterwards and has its separate set of valid usecases)
with arrow to where i think we should move Post to
ok yeah that makes much less sense now
although I still think new users are gonna fall to that
which is ok
I don't really see the issue with having a bit of an entry barrier on this
Post should be at the same point as onDamageTaken yeah
fuck it I'm fine with .Pre and .Post there then

I totally forgot we changed the ordering
LivingDamageAboutToApply
LivingDamageApplied
You're getting applied
Applied Energistics reference?
/s
Thats what I suggested
ah ok
I'm cool then
LivingIncomingDamageEvent
LivingShieldBlockEvent
LivingDamageEvent.Pre
LivingDamageEvent.Post
Is our current standing point?
sample size of 1
lol
qq: did the old events even have good javadocs? The case of many "really old" events is they didn't have any at all
I think that move might also make our patch blob smaller
Can the javadoc for all of them mention all the others
^ definitely should, and their intended usage on each
not really, but from the users I'd asked, they never even looked
can somebody also please make a docs PR to this
I have an @see DamageSequenceEvent which I would like to have the sequence explained there. trying to be DRY if possible
(or @quick kernel, update the gist and I'll slightly rewrite it and make it part of the docs)
nah that’s your job
I just want to have a reference point to work with
v good
very nice
I actually disagree with all of this /jkjkjk
Tbh I just read the javadoc on LivingHurt and man is that thing kinda useless
so @sand copper
Need to move damagetaken to below onDamageTaken call
- change damagetaken to
LivingDamageEvent.Post - change incomingdamage to
LivingDamageEvent.Pre - Change PreDamageEvent to
LivingIncomingDamageEvent - Change DamageBlockEvent to
LivingShieldBlockEvent
anything I missed?
Its overtechnical
LivingShieldBlockEvent is called DamageBlockEvent in the PR desc, is that on the PR desc or the actual code
updated
thanks
@lucid harbor
name change aside
should we add that boolean to skipping blockwithshield?
that still feels useful
heavy shield might not want to knock back when hit or be stunned, etc.
or might be a braced shield that can't be disabled by axe, etc.
Is it the blocking player's knockback or the attacker?
yeah, what exactly is that for
I feel like maybe that's a "don't do it yet and see if anyone needs it"
Since its non-breaking to add later
defender gets knocked back
players have their shield disabled
vanilla mobs do additional effects
Yeah lets leave it for now
so if I want my honey crystal shield to take say 1/6th of its durability off when blocking fire damage, which event would I use? The block damage one?
shieldblock yep
under what condition would that boolean be true
under whatever condition a user would want it to be
and will the PR now make shield damaging now apply cooldowns to modded shields? iirc it was hardcoded to vanilla shield
okay, under what condition would vanilla make this true
always
vanilla never would? what do you mean
Vanilla always calls blockWithShield if a block occurs
I'm not sure what the use case of this would be
#1198800008225501285 message
that's in Mob 
would be a separate PR I think
it's not even called from hurt
what is the semantic meaning of blockWithShield?
it's called from Mob#doHurtTarget lol
I say hold off on the extra flag for blockWithShield for now
does it mean "this damage is being blocked because the player is using a shield-like item", as opposed to "this damage is blocked because of an armor bonus or the like"
to an opt-in single boolean
yo utalking about the event or the method?
I'm talking about the proposed blockWithShield boolean
you might be missing some context
basically when a shield block is successfully made, the game reduces the damage & damages the shield (durability), thne calls blockUsingShield on the target entity
FYI, i'm not following the shield discussion, so please ping me with a summary once you all decide what we are going to do
that method is then used for things like the target mob being knocked back fro mthe impact
or the attacker disabling the shield with an axe
the proposal is to add a single boolean to the shieldblockevent to allow users to skip that specific call
for things such as un-disableable shields, shields that are considered too heavy to knockback, etc.
cus there's no other place to do so
so that they can do only the necessary logic themselves?
or no logic at all
cus you can't prevent the logic currently without mixin without this boolean
yeah if that's what they want yeah
if you block with a shield, you get all those effects, no exception
or only do axe logic, but no knockback logic or sum
Its patch complexity on our side and some added mental complexity to the user to think about when they need to raise the flag or not, as opposed to it just being implicit
but modded shields may not want that
I mean it defaults to vanilla
so it's really only if they want ti nteract with it
and it's not really patch complexity cus we're already wrapping the crap out of that subsection
so this would default to true?
hm, then what to name it
and you could flick it to do the opposite (skip the vanilla functionality)
callVanillaPostBlockBehavior feels clunky, but gets the point across fairly well I believe
even now the entire thing is basically just API wrapping
a single boolean conditional would hardly make a difference lol
yeah I'm all in for adding that boolean, just need to name it correctly
I'd be for some less-clunky variant of this
it should default to true
so the name should be inverse
skipVanillaShieldBlockHandling etc
unless it's a setter

the name for this sucks lol
but if skipVanillaShieldBlockHandling is the name, it should default to false, right?
because if we default to vanilla, then vanilla shield block behavior should run
(also I dislike shieldBlockHandling, I think shieldBlockPostBehavior is more exact)
the term "handle" is among the worst to use in a call chain because literally any piece of code can be "handling" something
DamageSequenceEvent is not, and should not be, directly invoked.
This disclaimer feels unnecessary in this state, abstract event classes throw anyway when you try to attach event listeners. Maybe do something like "DamageSequenceEvent provides a DamageContainer to its subclasses. Subscribe to the correct subclass of DamageSequenceEvent for your usecase." instead.
i like that.
oh yeah. reading the rest with that feels way more organic and informative
wt actual fuck. I can literally ctrl+click the symbol and get to the value. is this some weird load order thing with tests?
Alright. changes pushed. Tests passed. Let's merge this.
invuln thing?
right
So my problem with that event
Is the way that vanilla overrides isInvulnerableTo
ex: breeze
@Override
public boolean isInvulnerableTo(DamageSource p_312691_) {
return p_312691_.is(DamageTypeTags.BREEZE_IMMUNE_TO) || p_312691_.getEntity() instanceof Breeze || super.isInvulnerableTo(p_312691_);
}
Regardless of the event, the breeze is always invulnerable to BREEZE_IMMUNE_TO damage types, or to other breezes
but there isn't really anything we can do about it
yeah that's more of an issue with the event
than the captured boolean
which isn't really fixable unless we wanna patch everywhere
which I'm pretty sure we don't
so we just kinda went "ohwell, best we can do"
Yeah
the event is still worth having
it might be worth a warning at the class level though
Like in the event java doc?
Yeah
"This event may be unable to change the invulnerable status of some entities that override isInvulnerableTo against certain damage sources"
ehh
"This event may be skipped by some entities that override isInvulnerableTo and should not be considered a completely reliable indicator of existing invulnerability or incoming attacks"
maybe?
i already pushed Shadows' wording >.<
If the wording needs to be different to merge, i'll check it out in the morning. It's like 2 hours past my bed time. good night everyone.
shrug
Less critical
I do wonder if the damage container on the living entity should be a Stack of damage containers instead of a single object
Mostly because if someone calls hurt during the sequence from an event, it will not create a new container, but will null out the old container after it returns, and then crash at some indeterminate point later in the cycle
Makes sense. Though i need some help walking through this scenario.
Context: Player, LocalPlayer, and RemotePlayer have their own invocations of CommonHooks#onPlayerIncomingDamage (calls #1) which necessitates the instantiation of a DamageContainer before the one instantiated in LivingEntity#hurt. The current logic does a null check on the container field to prevent recreation of an existing container from an override method.
Problem: Since there is a possibility of infinitely recursive calls to hurt within damage listeners, we cannot assume the presence of a damage container is the instance for that level of recursion.
Solution Ideas:
LocalPlayerandRemotePlayerdon't use the event output in the return and still returnfalseandtruerespectively. What is the purpose of the event firing here that isn't available from the invocation inPlayerorLivingEntity?- as with the above,
Playeralso has its own invocation, but does cancel out early if the event is cancelled. However, the only logic inPlayerthat precedessuper.hurtis the damage scaling. Do we need this event invocation here?
a. note: the current PR stores the scaled damage in the damage container, but we could just pass it tosuper.hurtsince we don't track the pre-scaled damage - I propose removing
CommonHooks#onPlayerIncomingDamageand relying onCommonHooks#onLivingIncomingDamagefromLivingEntity#hurt, since they fire the same event anyways.
If we make that change, we can use a Stack and each invocation of LivingEntity#hurt would create a new one that it would also subsequently drop off at the end making for the LIFO behavior we want.
~~after writing this, this conversation sounds familiar.~~nvm I was thinking about the Player#actuallyHurt override conversation from a while back.
do the extra calls even need a damagecontainer?
LocalPlayer/RemotePlayer/Player#hurt
they seem like they're just meant to be standalone catches for extra stuff
If we create a special event that doesn't take a damage container and has no impact on subsequent logic, then sure. But these are copies of LivingIncomingDamageEvent that fire before the super.hurt gets called. On player this is a double firing of the event. On the local and remote sub-classes, there is no super, so it's the only invocation. I want to know why those events exist in the first place if listeners are using the same event as a regular livingentity event. There's nothing in the event that specifies it's for players only that would make it cleaner than an instanceof check. Seems out-dated to me
I guess the local and remote events make sense. We can pass in a damage container that isn't stored in the entity for the sake of the event. They don't call super so it's kind of an isolated posting.
The one in Player though seems ripe for removal
Then we could use the Stack<DamageContainer> exclusively in LivingEntity#hurt without losing track of each entry's parity with events.
could just give it a dummy instance of the container tbh
I'm not sure the container is even relevant there
that's what I was thinking. just instantiate one in the parameter line.
I'll push this to 1.21, we need to do a 1.20.6 stable
I don't think it even makes sense to fire the events from LocalPlayer or RemotePlayer
damage is a serverside concept
firing it on the client in some niche cases just makes it annoying to reason about
that's what I was thinking. I'll remove those patches, which is two less blobs on the patch count.
What about the one in Player though. vanilla only cancels if the damage is zero otherwise calls super, which would result in the same event being fired by LivingEntity. both Player and LivingEntity are both-sided. The only thing that happens between the two event firing that changes state is the damage modification on difficulty. I don't see how having the event fire before that adds value for modders, but it does create an imensely complicated issue for the goals of this PR.
I think its fine to just remove it as well. Damage scaling due to difficulty is effectively supposed to be "invisible"
Its just the mechanism of application. The alternative would be i.e. applying an attack damage modifier to every zombie in the world based on difficulty
but you wouldn't change how the event operates in that case
neat. that event hook was the only patch in RemotePlayer so that's one whole less file
we are up and running with Stacks for the damage container. i guess i'll just sit on this until we port to 1.21 then
I've lost track of where we're up to RE: the shield event, and also the potential associated boolean
My decision was to just leave it as-is currently in the PR
ok
PR needs its summary event names changed btw @sand copper
also
should we add helper methods to LivingIncomingDamageEvent for adding modifiers to the container?
to better indicate that:
- That's even an option now
- That event is the appropriate time/place to do so
I'll add some stuff to the PR
cus I just noticed a a new problem too
submitted review
and I've updated the attached writeup
@quick kernel getLast and peek do the same thing. The same is true for add and push. the only difference is the former are inherited methods from List whereas the latter are native to Stack. it's a nominal change, so i'm refactoring now.
does add not bypass this modCount incrementor?
peek also throws a more relevant exception if the stack happens to be empty
and doesn't instantiate a separate view and an iterator just to retrieve the element
peek just does a direct array lookup
yeah, i'm looking at that now.
While you're here, what are these helper methods you have in mind?
for the first event
yes. so just add a setReduction method that grabs the contianer for the user?
oh, right because we are passing functions to the method. wow i forgot we did that.
I left it as plural form of helper methods
because there's room there if we wanted to add overloads for each of the reduction types
for ease of use
but ultimately that's optional
kinda going backwards from the code reduction Shadow asked me to do in the container, but arguably a better place to have that kind of repetition
I agree but personally I think it serves a couple rather important benefits
if DRY is important here, just the one addReduction is fine
Changes addressed.
what else is affected that you think needs to be in that javadoc?
absorption i guess?
/**
* LivingDamageEvent captures an entity's loss of health. At this stage in
* the damage sequence, all reduction effects have been applied.
* <br>
* {@link Pre} allows for modification of the damage value before it is applied
* to the entity's health.
* <br>
* {@link Post} contains an immutable representation of the entire damage sequence
* and allows for reference to the values accrued at each step.
* <br>
* For more information on the damage sequence
*
* @see DamageSequenceEvent
*/
``` how's that?
word. it's a shame we are just a day too short for the 1.20.6 stable, but with 1.21 this week, i get why maty held off.
any chance this is going to get in early in the 1.21 neoforge cycle giving how breaking it is?
if he rebases, I'll take a look at it tomorrow / on Saturday™️
fixing the patches is always annoying. what do these symbols mean @@ -1127,23 +_,30 @@
its the hunk location of the conflict
the advise for rebasing patches is just to discard the entire thing and redo it
yes please
You can't "fix" them
don't try to fix them by hand
got it.
@gusty moss PR Rebased and tasks passed.
#1198800008225501285 message
[Reference to](#1198800008225501285 message) #1198800008225501285 [➤ ](#1198800008225501285 message)ok
PR needs its summary event names changed btw @sand copper
updated.
@gusty moss for the Mutable Damage Container. Would renaming InternalDamageContainer satisfy your comment or did you have something else in mind?
right now it's
DamageContainer interface
InternalDamageContainer mutable implementation
ResultDamageContainer immutable implementation
no, i don't want ResultDamageContainer to have any set methods
i suggest DamageContainer and MutableDamageContainer extends DamageContainer
so no interface, just an immutable class and a mutable sub-class?
currently ResultDamageContainer doesn't have any set methods because it's a record. the two that we do have throw errors to inform the developer that they've tried to invoke a set method during an immutable event
i want the containers to be typesafe when they're mutable in mutable events and immutable in immutable events
an immutable class with a mutable sub-class doesn't make sense
that'd mean the fields in the immutable would have to be mutable
currently the events do handle mutability. the only event in which the container is immutable is the last one LivingDamageEvent.Post which takes the internally mutable container as a parameter but stores it as an immutable container within the event so that listeners have an immutable container in that event without impacting the actual mutable container on the entity
yes you're missing the point
although hmm
no yeah
the event shouldn't expose an object with set methods if those set methods throw
if we're making this as clear as possible for modders, it should also be using types safely
what about this. what if we have only one Mutable DamageContainer object and we simply add the final values of what would be the immutable version as fields in the one and only event that is meant to be immutable. that eliminates the set methods and the type references
sure
okay nevermind, the damage events all extend the sequence event which takes the container. so i'd have to pass in a null or otherwise immutable container anyways or break the Pre/Post format completely just to have an event that doesn't take a container
So then i guess instead of throwing, the set methods should just do nothing instead?
no no
that's even more confusing
it shouldn't have a set method if it can't set
that's why i suggested 2 interfaces
since in events with mutable you can just override in the event to return a mutable container
i'm not tracking what you mean by this
class DamageEvent {
DamageContainer getContainer();
}
class LivingBlahBlahPre {
@Override MutableDamageContainer getContainer() { return (MutableDamageContainer) super.getContainer(); }
}
okay let me rephrase. in what scenario would someone be implementing this override?
it's not someone implementing it?
it's the event subclasses
since you use a superclass with a damagecontainer
so you're worried about people extending DamageSequenceEvent with unsafe overrides? wouldn't that still be the case if someone overrode the sub-classes in the same way?
Are we talking about people posting events instances or listener implementations?
uhm no? i'm worried about LivingDamageEvent.Post extending damagesequenceevent
which currently directly provides access to a damage container with set methods
Then we need to yeet the DamageSequenceEvent so that each of the current sub-classes takes the appropriate container explicitly and only extends LivingEvent
At that point the damage containers wouldn't need any inheritence at all because each event would be using it's own object with the first three events using the same type of object
So we end up with ```java
record ImmutableDamageContainer(...){}
class MutableDamageContainer{}
class LivingIncomingDamageEvent extends LivingEvent {
MutableDamageContainer container;
public LivingIncomingDamageEvent(LivingEntity entity, MutableDamageContainer container) {super(entity); this.container = container;}
}
//repeat for LivingShieldBlock and LivingDamageEvent(.Pre)
class Post extends LivingDamageEvent {
ImmutableDamageContainer container;
public Post(LivingEntity entity, ImmutableDamageContainer container) {super(entity); this.container = container;}
}
alternatively the Post method doesn't need to have a container. as with one of my previous suggestions, it could just have final fields for all of the container properties which provide an immutable representation of the values. It would mean one less class in the codebase
Then we would just have one DamageContainer that was inherently mutable without needing an immutable counterpart
sure
sounds good. i'll make those changes now
Alright. changes made. Tests passed. lmk if there's anything else that needs updated. I believe all the javadocs are still correct, but I may have missed some details
did a final cleanse of the javadocs and cleaned up some formatting the the IDE had thrown in there arbitrarily.
javadoce formaatting addressed.
@neon anvil comments addressed. ping me if you want to discuss more.
Shadow is the residential ASM subject matter expert if you want him to write one lol
The entity hurt thing… my code is multiloader so adjusting it to do your suggestion will be… painful for me
So just note that multiloader people may bypass some of your events
in that case, i think the suggestion about using super.hurt at the end might be the better approach for your use case
Do any of the lower level events allow modders to change the damage? Like lower than hurt
that's already the case tbh
LivingDamageEvent.Pre which is within LivingEntity#actuallyHurt.
There's also LivingShieldBlockEvent which also fires in hurt and will accept changes to the damage.
The mechanism for doing that kind of call-site mass replacement is currently inoperable (the method used to scan the call sites hasn't been re-added in NG)
Otherwise it would be a good use of it
That being the case, can we resolve that comment?
Ya
Could leave a todo to mention to re-evaluate with asm once the method is added to NG
yes
yes. After Maty's review it added too much restriction on type-safety for the events so it was removed.
@lucid harbor why? this comment that would essentially make it the same as the method it is patched into, which is very different from the rest of the method names in CommonHooks
Virtually all the method names in commonhooks are junk
The name should reflect the parameters and result of the method
A method name of onXYZ for something that returns a value is incorrect
because it isn't a response
🤔 at this point, it's not important enough for me to fight if we want this merged. I'll change it.
I have been meaning to write up a set of standard things as far as hook names and event conventions
That'd be nice
but I am quite short on time :p
mood
I think we're at a "good enough" point now
Looks like Maty's review needs to be approved for the merge.
yeah, I have been meaning to do a pass over the event names and CommonHooks callers
but similar to you, short on time
I said I'll merge it on monday, there's still time dw lol
Hey uh, was knockback affected by this PR?
https://github.com/neoforged/NeoForge/issues/1173
no
No, but we might want to drop the @ApiStatus.Internal annotation from DamageContainer. It's throwing a lot of IDE warnings in userdev.
nothing critical, just slightly annoying
ah. I'll make PR tonight if I got time
@swift bluff close the one you triaged as duplicate lol
It was leftover from when DamageContainer was an interface. Since it didn't throw any warnings in gametests, i never noticed.
I also think we could use some extra helper methods on some of the events to reduce the event.getContainer.xyz() bloat. i'll open another PR for the QOL changes
these won't be breaking though

yeah the helper methods would be good for sure
I might hold off porting until that's in
Just fyi, you can build your mod against a neo pr to see how it works in actual practice
I know. I ported pmmo to 1.21 using the port PR. Pmmo is a bit of a beast to just casually port to a pr in a test branch though. I should probably make a userdev mod just for PR testing though. That's probably going to come in handy.
Am I reading DamageContainer#setReduction wrong, or do the reductions not actually modify newDamage there? (Basically trying to determine if there is a clean way to move the protection the mekasuit gives to the reduction system rather than just directly modifying the total damage in the event. And then after I figure out if there is a clean way, I have to figure out which way makes more sense to have it mechanically)
Iirc setting a reduction doesn't immediately force a computation, but it will recalc when getNewDamage is called
getNewDamage is a simple getter
the reduction functions apply during the vanilla armor rduction logic. Basically the sequence is Vanilla calculates a reduction => reduction functions operate on the output value => new damage is modified according to the final output
this.reductions.put(reduction, modifyReduction(Reduction.ABSORPTION, amount));
this.newDamage -= Math.max(0, amount);
shouldn't the modifyReduction be set as the new value of amount
before the newDamage -= line?
that's what I am talking about
also actually
why does it pass it as modify absorption rather than the passed in reduction?
you are correct. the modified amount is not being applied to the new damage.
it should be ```java
float newReduction = modifyReduction(reduction, amount)
this.reductions.put(reduction, newReduction);
this.newDamage -= Math.max(0, newReduction);
also some of the logic in actuallyHurt seems a bit wonky. Given CommonHooks.onLivingDamagePre returns newDamage, but unless my inutition is wrong, then it does float f = newDamage - newDamage, so shouldn't that always be equal to zero?
and setAbsorptionAmount just above that line is like absorption reduction - new damage + 0 OR absorption reduction - new damage + new damage - absorption reduction (which that is equal to zero)
so feels like thatlogic could be cleaned up
I think that about covers all the comments of things that seem weird or even straight up wrong from my work on switching mek to using the new pipeline
I made it draft to get more feedback, but if we want to merge just for the bugfix, let me know.
What are your thoughts on that ^ message and the one just after it
I don't have a thing on me, can you show me the javadoc for the pre/post events when you get a sec
investigating that one now
/**
* LivingDamageEvent.Post is fired after health is modified on the entity.<br>
* The fields in this event represent the FINAL values of what was applied to the entity.
* <br>
* Also note that appropriate resources (like armor durability and absorption extra hearts) have already been consumed.<br>
* This event is fired whenever an Entity is damaged in {@code LivingEntity#actuallyHurt(DamageSource, float)}
* <br>
* This event is fired via {@link CommonHooks#onLivingDamagePost(LivingEntity, DamageContainer)}.
*
* @see DamageContainer for more information on the damage sequence
**/
public static class Post extends LivingDamageEvent {
and ```java
/**
* LivingDamageEvent.Pre is fired when an Entity is set to be hurt. <br>
* At this point armor, potion and absorption modifiers have already been applied to the damage value
* and the entity.<br>
* This event is fired in {@code LivingEntity#actuallyHurt(DamageSource, float}
* <br>
* For custom posting of this event, the event expects to be fired after
* damage reductions have been calculated but before any changes to the entity
* health has been applied. This event expects a mutable {@link DamageContainer}.
* <br>
* This event is fired via the {@link CommonHooks#onLivingDamagePre(LivingEntity, DamageContainer)}.
*
* @see DamageContainer for more information on the damage sequence
**/
public static class Pre extends LivingDamageEvent {
@quick kernel
I'm wondering whether it's worth including something in each of the javadocs stating what the primary use of the event is
as one last nip in the issue of players using the wrong event for things
or maybe just one note in the .Pre event saying if you are just modifying the damage, you should be using incomingdamage if at all possible
maybe change void setNewDamage to setNewDamageOnlyIfImANoobAndRefuseToUseIncomingDamageEventProperly
maybe void overrideSequenceDamageValue(float overrideValue)
with a javadoce stating that LivingIncomingDamage is the correct place to make damage changes unless the intention is to alter damage after the armor and magic resist applied to the OG damage
nah keep the method name, it's fine
just a basic note
it's more so we have something in case people only look at that event
okay, so yeah the absorption also needs tweaked. this is the current code (FQNs removed for readability)java this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainers.peek().getNewDamage()); //properly sets the absorption amount in the reduction map, however modifies the newAmount value in the process this.damageContainers.peek().setReduction(Reduction.ABSORPTION, this.getAbsorptionAmount()); //Attempts to calculate a temporary holder variable for the post-absorption damage amount, but is using the already reduced value float f1 = Math.max(this.damageContainers.peek().getNewDamage() -this.damageContainers.peek().getReduction(Reduction.ABSORPTION), 0.0F); //just mathematically always equals zero. this.setAbsorptionAmount(this.damageContainers.peek().getReduction(Reduction.ABSORPTION) - (this.damageContainers.peek().getNewDamage() - f1)); //properly grabs the newDamage value after the event hook, but the damage in was busted from the start. f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainers.peek()); if (f1 <= 0) return; new code (same thing with the FQNs) ```java
this.getDamageAfterMagicAbsorb(p_21240_, this.damageContainers.peek().getNewDamage());
//works exactly the same
this.damageContainers.peek().setReduction(Reduction.ABSORPTION, this.getAbsorptionAmount());
//removed the temporary variable as it wasn't needed. Both the absorption reduction and newDamage value are what we want them to be already
//instead we reduce the actual absorption amount by the reduction (which may be larger from events for the sake of uber-absorption effects) but we can't
//actually reduce it less than zero so we clamp.
this.setAbsorptionAmount(Math.min(this.damageContainers.peek().getReduction(Reduction.ABSORPTION), this.getAbsorptionAmount()));
//event now has the correct amount going in
float f1 = net.neoforged.neoforge.common.CommonHooks.onLivingDamagePre(this, this.damageContainers.peek());
if (f1 <= 0) return;
@echo kiln ^ sound about right?
get a couple opinions before submitting just in case
I don't have time to look myself atm
it's in draft right now as I expect probably a few more things we didn't think of
yeah
just want to try get this in as quick as possible since it's basically an addendum to an existing PR
agreed. the reduction thing is absolutely a bug that makes that non-working
huh, it seems like everything introduced in that pr but the actual damage events had tests added
I can add them in the addendum PR
you know what time it is, right?
write a test for those events to make sure that the modifier thing is fixed (if you didn't already in your PR)
I will look when I get back to my pc. Reading code blocks on mobile is a pain (ps: set a language type so that discord does some coloring)1
I did. but mobile doesn't recognize java
Ah
I think?
anyone know how to debug with gametests? IntelliJ only captures breakpoints in the base module not the neoforge module with the patches applied, so I can't even breakpoint my own patch code.
i'll play around with my IDE and see if it's a local issue
whoever wrote this... thank you it's so clear 😄
- isn't capitalised though and we should potentially consider execution for treason
if that's not sarcasm. you're welcome
also, #3 shoudl be is not in
it's not
smh, not using tone indicators for sarcasm or joking
banned /jk
@sand copper
if someone wanted to modify the damage to increase at a reductio nstage
is that even possible currently
like what if I have a mob effect that increases damage taken
as best I can tell that's not possible in a proper fashion because you've clamped the reduction (since the whole system is built on reductions rather than modifications)
which then leads to a conflict of naming between addModifier which isn't a modifier, only a reduction function
🤔 I don't see why that shouldn't be possible.
the value is reduced, right?
so they'd have to provide a negative value
which isn't possible cus you clamp it to 0 min?
the whole idea of having to provide negative values is a bit odd though
or at least feels it.. idk
Reducing by a negative would have that effect, yes. I think since the pipeline views them as reductions on the damage, it make sense to describe and treat them like reductions. However allowing the system to invert that assumption makes sense for those who find utility in that kind of modification.
yeah but you clamp it at 0? so you can't do a negative can you?
Not currently. We were discussing changing that I thought
?
yes we currently clamp. no it doesn't have to be. that's what we are talking about changing.
Ah
I've run into an issue with building the gametest for this and i'd like some input. The main issue is how to capture succeed/fail conditions within an event listener. This may be an XY issue, but i'll circle back to that. I attempted to get around this, by caching values in the scoreboard and then checking them in the gametest sequence. This works, however, serverplayers have spawn invulnerability, that I cannot override without an AW so the call to GameTestPlayer#hurt always results in zero damage. So while players can store values in the scoreboard, they don't take damage. If i use a zombie instead, i can deal the damage, but I can't store in the scoreboard.
Where this might be XY is that my approach to the gametest may be the source of my problem. The structure of the gametest is essentially ```
test -> register LivingIncomingDamageEvent, modify damage, and set reduction functions
test -> register LivingDamageEvent.Pre, store post-reduction values, store current newDamage, set damage to zero
test -> register LivingDamageEvent.Post, confirm health change matches expected difference
test -> start sequence with player, give armor, enchant armor, give absorption, give resistance effect, hurt player.
If I could fail a test in an event listener, this would be easy, but the only way I found to do that (which wasn't reliable) was to us an atomic object of type consumer, store the `message -> helper.fail(message)` method in there and `get()#accept` in the event listener, but that just felt clunky and hacky.
I realize i could just have the gametest wait out the spawn invulnerability, but i'd still like to know if there's a better way to fail a test within a event listener.
figured it out. just stored the values in the entity's persistentData and added an idle time to the sequence to let the invul fall off
note that persistent data has a non-zero chance of being removed in the future™️
probably something for the person doing that removal to fixup 
It honestly just needs to be somewhere in the entity NBT, so if you have a location that's more futureproof, i'll use that
"more futureproof" would be adding an attatchment
that seems overkill for a gametest, unless you think otherwise
not really, we have helpers to register attachments easily
IDEA doesn't understand {@return} fully correctly
particularly, nested javadocs tags (like {@link} in {@return})
a bug with IDEA
nah, that's semantically equivalent to having it spread on three lines
IDEA understands @return the block tag fine -- it's {@return} the inline tag that it has trouble with at present
nope
well yeah it's the inline tag
but specifically it's the braces
this works fine
yeah, because when it's not an inline tag it's a block tag, which IDEA works fine with
Yeah, {@return ...} doesn't support nested tags
If a javadoc needs nested tags it just shouldn't use {@return }
then just remove the braces lol
Don’t forget about this, unless you just have it chilling locally
it supports them in the html render iirc, it's just that intellijs messy code doesn't
