Skip to content

Refactor environment effect lookup#278

Merged
MikeJeffers merged 9 commits intoOpenPerpetuum:Developmentfrom
Veritania:refactor-environment-effect-lookup
Mar 12, 2021
Merged

Refactor environment effect lookup#278
MikeJeffers merged 9 commits intoOpenPerpetuum:Developmentfrom
Veritania:refactor-environment-effect-lookup

Conversation

@Veritania
Copy link

@Veritania Veritania commented Mar 9, 2021

Looking for feedback. Trying to tackle Issue #251

I'm not a fan of just using raw strings to define day/night/good/bad/neutral, but went with it for now due to WeatherInfo.cs and GameTimeInfo.cs returning booleans for these same values.

@MikeJeffers
Copy link

Hey this is great! Happy someone picked up one of the refactoring issues.
Anything to clean up all the nested conditionals is a win. I think your strategy to assign strings to each state is a fine approach and would be happy to review and merge as-is.

If you are feeling ambitious, maybe those functions return a DayState or WeatherState enum so you don't have string literals floating about, and the methods might not be IsDay or IsNight but GetDayState allowing us to have more nuanced segments of day or weather.
But that can be a separate PR for later, totally up to you!

Thank you for the PR!!

@Veritania
Copy link
Author

Hi, thank you for taking a look at it! I'm happily surprised about the positive enthusiasm :)

I've tried to add the enums DayState and WeatherState as you recommended, and the EventHandler is now using those to determine the next weather effect.

}
else

//In cases where DayState is supposed to stay "neutral", WeatherState cannot also be "neutral" if we are to follow the logic this change is replacing.
Copy link
Author

@Veritania Veritania Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can happen when both

WeatherInfo(Between GOOD_WEATHER = 100 and BAD_WEATHER = 200)
and
GameTimeInfo (Between NIGHT_END = 100 and DAY_START = 200)

hits some of their undefined gaps at the same time, where it's neither Day or Night / Good or Bad. So now they would default to 'NEUTRAL'.

Old logic just did nothing in that case, but here we would try to lookup a value in the _weatherDict which does not exist (neutral, neutral).

So to avoid that lookup, I just return;
But I'm not sure if we ever have a scenario where both of them hits these gaps at the same time.

Copy link

@MikeJeffers MikeJeffers Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, both weather and daytime can have a neutral state and not have any zone effect.
So its a bit weird, but you do need to allow it to look up a null-entry so that it will cancel the current zone-effect.
The isSameEffect logic handles this stuff.
So in this case, you shouldn't actually return, but let the ZoneEffect nextEffect = null; carry through and cancel the current effect.
tl;dr don't return, and add an entry for null in your dictionary - should achieve the desired outcome

I'll pull the code and test it out locally soon, but I do remember this is a state that the effect can/should be in when both are 'neutral' states.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the insight!

I have now flipped the logic of the if statement, so that if both are in the neutral state we don't touch the initial ZoneEffect nextEffect = null and pass it to the isSameEffect unchanged. It should have the same result as you described.

If you instead prefer that there is a null entry in the dictionary, I'd have to look into how to solve that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just add another entry with {(neutral, neutral): null} and let it look up and get the null value from the dict.
That way you avoid that one remaining if statement wrapping the lookup - that way the mapping is all contained in the dictionary.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed #a35a0f2 which tries to achieve that.
There is no longer any if statement, and the dictionary contains an entry for neutral+neutral which returns null.

The alternative to having dynamic instead of EffectType as the expected values in the dictionary, was to mark it with EffectType? as a nullable. But that had some ripple-effects throughout the class, affecting the other dictionary and methods.

So I think this looks a little cleaner in comparison.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, hang on a sec. I just realized you are creating a dictionary of EffectTypes and not the ZoneEffect instances - which means we can simplify this into one dictionary! (woo!) No dynamic type, and you have a nullable class instance.

You see the collection that is made here? https://github.com/OpenPerpetuum/PerpetuumServer/blob/Development/src/Perpetuum/Services/EventServices/EventProcessors/EnvironmentalEffectHandler.cs#L37-L45
Instead of having that key on EffectType have it key on your Tuple of Time/weather states!
That way you save creating another static dictionary, avoid using dynamic, and skip a lookup (O(1), but still more to maintain).
Then GetEffect would have a signature like: ZoneEffect GetEffect(GameTimeState, WeatherState) or the tuple, either way. (maybe cleaner to create the tuple in the helper method?)

Sorry I did not look closely enough to realize you were replacing that dictionary, and it works and cleans up a lot of code, but if you want to this extra tweak will really make this a killer PR!
This is the danger of not pulling the code first before reviewing 🤦

Let me know if this makes sense or if you have any questions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback. I think I understand what you mean.
I've pushed #3976274 to try and meet those requirements.

I'm at fault here, for not having better understanding of the code base I'm making changes to.
But I'm happy that I can receive guidance from you, and please be critical. I want to continue learning from this, and hopefully contribute value in the process.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to hear! I want open source projects like this to be opportunities for people to learn and work on things they otherwise might not be able to build themselves. But also don't want to make it too hard to contribute either. Either way I'll work with you to make sure you get your code in the repo.

The changes look good! I'll get you a review and maybe a merge later this evening.
And don't worry, we are still learning the codebase ourselves too ;)

@Veritania Veritania marked this pull request as ready for review March 10, 2021 11:51
@Veritania Veritania changed the title WIP: Refactor environment effect lookup Refactor environment effect lookup Mar 10, 2021
@MikeJeffers MikeJeffers added the Refactor Code maintainability, style, or other non-functional changes label Mar 10, 2021
Copy link

@MikeJeffers MikeJeffers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one line change to consider

}
}

nextEffect = GetEffect(_gameTime.GetDayState(), _weatherState.getWeatherState());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not simply declare and initialize nextEffect here? (why have ln61?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var nextEffect = GetEffect(_gameTime.GetDayState(), _weatherState.getWeatherState()); basically.
^ var can be used because its no longer initialized with null.

Style nit: Also there is some trailing whitespace on this line. (I finally pulled the code!)

}
}

nextEffect = GetEffect(_gameTime.GetDayState(), _weatherState.getWeatherState());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var nextEffect = GetEffect(_gameTime.GetDayState(), _weatherState.getWeatherState()); basically.
^ var can be used because its no longer initialized with null.

Style nit: Also there is some trailing whitespace on this line. (I finally pulled the code!)

@MikeJeffers
Copy link

Tested! Working as intended.
Feels so good to see this refactored... OnStateChange is so clean now :)

@Veritania
Copy link
Author

Latest commit should resolve your requests :) Thank you for the review

Copy link

@MikeJeffers MikeJeffers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work @Veritania !
Congratulations on your first contribution 🎉

@MikeJeffers MikeJeffers merged commit cde8bd6 into OpenPerpetuum:Development Mar 12, 2021
@Veritania Veritania linked an issue Mar 22, 2021 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P21 Refactor Code maintainability, style, or other non-functional changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Environ effect lookup table/dict refactor

2 participants