Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Power Creeps and Effects #258

Merged
merged 12 commits into from
Dec 27, 2019

Conversation

shanemadden
Copy link
Collaborator

@shanemadden shanemadden commented Oct 23, 2019

Added power creeps and the necessary game and power spawn object interfaces to work with them, as well as effects on room objects which are used by both power creeps and strongholds.

Effects can have types representing powers or 'natural effects' (which only strongholds use currently) - this is set up as a nested enum to keep PowerType distinct from EffectType, though these could also just be a single enum with the relevant integer representations of both power and natural effects if that's overcomplicating things.

Implementations on creeps which are identical to those on power creeps have been moved to a SharedCreepProperties trait which both creeps and power creeps use - I'm not a huge fan of this naming if there's other ideas.

Several attributes on power creeps not spawned in the world are undefined in the same way as the issue reported in #246, causing a number of potential panics. This switches just the directly-impacted functions to return a Result, which might be a start toward #3 - currently just bubbling up serde's ConversionErrors which seems potentially not ideal? If this ends up being the final implementation it's probably a good time/release to make similar result changes in other places.

Resolves #158

src/objects.rs Outdated
@@ -120,12 +122,12 @@ reference_wrappers! {
///
/// This can be freely implemented for anything with a way to get a position.
pub trait HasPosition {
fn pos(&self) -> Position;
fn pos(&self) -> Result<Position, ConversionError>;
Copy link
Collaborator

@daboross daboross Oct 24, 2019

Choose a reason for hiding this comment

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

While this technically solves the problem, I'd argue changing the traits like this doesn't really take advantage of the type system we have.

Specifically, changing the traits like this requires everyone to deal with usually-non-existent error cases dealing with every other non-power-creep object.

In addition, this makes methods like .get_range_to panic when called with a power creep, and there's no indication in the code that something dangerous has happened. If users had to manually unwrap a PowerCreep result in order to do this, I think that could make things clearer.

The idea I'm coming from here is that ideally, things which behave differently or could fail should be dealt with explicitly by consumers. Users of the crate should be forced to deal with error cases, and shouldn't be able to write code which has a chance of failing at runtime without knowing (without doing an .unwrap() or .expect() somewhere in their own code).

What would you think of just not implementing HasPosition and other traits for PowerCreep and instead requiring first converting to an "InstantiatedPowerCreep" or similar before being able to call relevant methods? Or if not that, what are your thoughts on this problem?

Edit: edited shortly after posting to refine my thoughts better.

Copy link
Collaborator Author

@shanemadden shanemadden Oct 24, 2019

Choose a reason for hiding this comment

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

Agreed, this kind of change to these methods makes them a lot more awkward to use - my initial attempt at implementation used an enum to wrap an alive-or-dead-power-creep, but that ended up being a mess - this sounds better ;)

The comparison I'm thinking of is that we'd have something akin to a std::rc::Weak upgrade into a std::rc::Rc - taking the maybe-alive-power-creep object reference and upgrading it to get a we-know-it's-alive object with room object properties, HasId, Attackable etc.

Because this is only applicable to the results of accessing game::power_creeps (and game::creeps in the #246 case) case and not for objects found via find()/look(), my thinking is to have PowerCreep as the 'fully alive power creep' representation (which would be the find/look result, intuitively) and to add PowerCreepInfo or GamePowerCreep or somesuch which would be the version of the reference returned by game::power_creeps::* that can be upgrade()-ed to a full PowerCreep if it's spawned on the current shard.

I could use some guidance on how to get this implemented - I can't quite get my head around how to get that 'upgrade()' function set up to get the underlying js ref moved from PowerCreepInfo/ShrodingersPowerCreep to PowerCreep during the upgrade(), to get it converted to Option<PowerCreep>.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Worked it out and went with AccountPowerCreep, should be a much less breaking changeset now :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Awesome!

The comparison I'm thinking of is that we'd have something akin to a std::rc::Weak upgrade into a std::rc::Rc - taking the maybe-alive-power-creep object reference and upgrading it to get a we-know-it's-alive object with room object properties, HasId, Attackable etc.

This sounds like a sane comparison to me. The new scheme looks good!

Copy link
Collaborator

Choose a reason for hiding this comment

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

ShrodingersPowerCreep

🤣

I think I like it better than AccountPowerCreep 😛

@shanemadden
Copy link
Collaborator Author

Ok, last implementation question - should I add a wrapper around game::creeps::* returns to account for the potentially missing id in #246 in the same way AccountPowerCreep does for power creeps or leave fixing that for another time?

Copy link
Collaborator

@ASalvail ASalvail left a comment

Choose a reason for hiding this comment

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

This is another one that is looking quite good!

src/constants/types.rs Outdated Show resolved Hide resolved
@ASalvail
Copy link
Collaborator

Ok, last implementation question - should I add a wrapper around game::creeps::* returns to account for the potentially missing id in #246 in the same way AccountPowerCreep does for power creeps or leave fixing that for another time?

This one's big enough already. I suggest keeping it separate. PRs aren't expensive!

@shanemadden
Copy link
Collaborator Author

@ASalvail @daboross Have a couple more minor changes on here that could use a quick eyeball before they get merged - thanks!

Copy link
Collaborator

@ASalvail ASalvail left a comment

Choose a reason for hiding this comment

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

Changes look good. Thanks!

@@ -276,8 +276,7 @@ pub const INVADERS_ENERGY_GOAL: u32 = 100000;

pub const SYSTEM_USERNAME: &str = "Screeps";

pub const SIGN_PLANNED_AREA: &str =
"A new Novice or Respawn Area is being planned somewhere \
pub const SIGN_PLANNED_AREA: &str = "A new Novice or Respawn Area is being planned somewhere \
Copy link
Collaborator

Choose a reason for hiding this comment

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

rustfmt changed it's default value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The joys of the nightly branch apparently!

js_unwrap! { @{self.as_ref()}.attack( @{target.as_ref()} ) }
}

pub fn heal(&self, target: &Creep) -> ReturnCode {
pub fn heal<T>(&self, target: &T) -> ReturnCode
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you heal enemy creeps?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yup, sure can! You usually wouldn't want to, but there is a useful uncommon case in healing allies' creeps (though my intent for this change was just to make it consistent with the args for the heal function on Creep)

@shanemadden shanemadden merged commit 751af23 into rustyscreeps:master Dec 27, 2019
@shanemadden shanemadden deleted the power_and_effects branch December 27, 2019 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement changes from the power creep era update
3 participants