Skip to content

Commit

Permalink
contracts: only lock structure resources when battle starts
Browse files Browse the repository at this point in the history
  • Loading branch information
credence0x committed Sep 15, 2024
1 parent 3a5d5d0 commit 29c2dcf
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 15 deletions.
4 changes: 2 additions & 2 deletions client/src/dojo/contractComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -983,12 +983,12 @@ export function defineContractComponents(world: World) {
ResourceTransferLock: (() => {
return defineComponent(
world,
{ entity_id: RecsType.Number, release_at: RecsType.BigInt },
{ entity_id: RecsType.Number, start_at: RecsType.BigInt, release_at: RecsType.BigInt },
{
metadata: {
namespace: "eternum",
name: "ResourceTransferLock",
types: ["u32", "u64"],
types: ["u32", "u64", "u64"],
customTypes: [],
},
},
Expand Down
47 changes: 36 additions & 11 deletions contracts/src/models/combat.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ impl ProtecteeCustomImpl of ProtecteeCustomTrait {
self.protectee_id != 0
}

fn protected_resources_holder(self: Protectee) -> ID {
fn protected_entity(self: Protectee) -> ID {
if self.is_other() {
self.protectee_id
} else {
Expand Down Expand Up @@ -522,9 +522,30 @@ impl BattleSideIntoFelt252 of Into<BattleSide, felt252> {

#[generate_trait]
impl BattleEscrowImpl of BattleEscrowTrait {
fn deposit_lock_immediately(ref self: Battle, world: IWorldDispatcher, army_protectee: Protectee) {
let army_protectee_id = army_protectee.protected_entity();
let mut army_resource_lock: ResourceTransferLock = get!(world, army_protectee_id, ResourceTransferLock);
army_resource_lock.assert_not_locked();

let now = starknet::get_block_timestamp();
assert!(army_resource_lock.start_at > now, "wrong lock invariant (1)");
assert!(army_resource_lock.release_at > now, "wrong lock invariant (2)");

army_resource_lock.start_at = now;
set!(world, (army_resource_lock));
}


fn deposit_balance(ref self: Battle, world: IWorldDispatcher, from_army: Army, from_army_protectee: Protectee) {
let from_army_protectee_id = from_army_protectee.protected_resources_holder();
let from_army_protectee_id = from_army_protectee.protected_entity();
let from_army_protectee_is_self: bool = !get!(world, from_army_protectee_id, Structure).is_structure();

// ensure resources were not previously locked
let mut from_army_resource_lock: ResourceTransferLock = get!(
world, from_army_protectee_id, ResourceTransferLock
);
from_army_resource_lock.assert_not_locked();

if from_army_protectee_is_self {
// detail items locked in box
let escrow_id = match from_army.battle_side {
Expand Down Expand Up @@ -552,15 +573,18 @@ impl BattleEscrowImpl of BattleEscrowTrait {
Option::None => { break; }
}
};
}

// lock the resources protected by the army
let mut from_army_resource_lock: ResourceTransferLock = get!(
world, from_army_protectee_id, ResourceTransferLock
);
from_army_resource_lock.assert_not_locked();
from_army_resource_lock.release_at = Bounded::MAX;
set!(world, (from_army_resource_lock));
// lock the resources protected by the army immediately
from_army_resource_lock.start_at = starknet::get_block_timestamp();
from_army_resource_lock.release_at = Bounded::MAX;
set!(world, (from_army_resource_lock));
} else {
// lock resources of the entity being protected starting from
// when the battle starts to account for battle.start_at delay
from_army_resource_lock.start_at = self.start_at;
from_army_resource_lock.release_at = Bounded::MAX;
set!(world, (from_army_resource_lock));
}
}

fn withdraw_balance_and_reward(
Expand All @@ -572,7 +596,7 @@ impl BattleEscrowImpl of BattleEscrowTrait {
BattleSide::Defence => { (self.defenders_resources_escrow_id, self.attackers_resources_escrow_id) }
};

let to_army_protectee_id = to_army_protectee.protected_resources_holder();
let to_army_protectee_id = to_army_protectee.protected_entity();
let to_army_protectee_is_self: bool = !get!(world, to_army_protectee_id, Structure).is_structure();

let winner_side: BattleSide = self.winner();
Expand Down Expand Up @@ -660,6 +684,7 @@ impl BattleEscrowImpl of BattleEscrowTrait {
// release lock on resource
let mut to_army_resource_lock: ResourceTransferLock = get!(world, to_army_protectee_id, ResourceTransferLock);
to_army_resource_lock.assert_locked();
to_army_resource_lock.start_at = starknet::get_block_timestamp();
to_army_resource_lock.release_at = starknet::get_block_timestamp();
set!(world, (to_army_resource_lock));
}
Expand Down
6 changes: 6 additions & 0 deletions contracts/src/models/resources.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub struct OwnedResourcesTracker {
pub struct ResourceTransferLock {
#[key]
entity_id: ID,
start_at: u64,
release_at: u64,
}

Expand All @@ -106,6 +107,11 @@ impl ResourceTransferLockCustomImpl of ResourceTransferLockCustomTrait {

fn is_open(self: ResourceTransferLock) -> bool {
let now = starknet::get_block_timestamp();
if self.start_at.is_non_zero() {
if now < self.start_at {
return true;
}
}
now >= self.release_at
}
}
Expand Down
15 changes: 13 additions & 2 deletions contracts/src/systems/combat/contracts.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -678,8 +678,9 @@ mod combat_systems {
battle.defence_army_health = defending_army_health.into();
battle.last_updated = now;
battle.start_at = now;
// add battle start time delay when a structure is being attacked.
// if the structure is the attacker, the battle starts immediately
if defending_army_protectee.is_other() {
// add delay when a structure is being attacked
battle.start_at = now + battle_config.battle_delay_seconds;
}

Expand Down Expand Up @@ -735,12 +736,17 @@ mod combat_systems {
assert!(defending_army.battle_id == battle_id, "army is not in battle");
assert!(defending_army.battle_side == BattleSide::Defence, "army is not on defensive");

let mut defending_army_protectee: Protectee = get!(world, defending_army_id, Protectee);
// this condition should not be possible unless there is a bug in `battle_start`
assert!(defending_army_protectee.is_other(), "only structures can force start");

let now = starknet::get_block_timestamp();
let mut battle = BattleCustomImpl::get(world, battle_id);
assert!(now < battle.start_at, "Battle already started");

// update battle
battle.start_at = now;
battle.deposit_lock_immediately(world, defending_army_protectee);
set!(world, (battle));
}

Expand Down Expand Up @@ -1344,7 +1350,12 @@ mod combat_systems {
set!(world, (structure_protector, Protectee { army_id, protectee_id: army_owner_id }));

// stop the army from sending or receiving resources
set!(world, (ResourceTransferLock { entity_id: army_id, release_at: Bounded::MAX }));
set!(
world,
(ResourceTransferLock {
entity_id: army_id, start_at: starknet::get_block_timestamp(), release_at: Bounded::MAX
})
);
army_id
}

Expand Down

0 comments on commit 29c2dcf

Please sign in to comment.