From bc06629525b5b7b7a73448ec6d239bf42bf7797c Mon Sep 17 00:00:00 2001 From: loothero <100039621+loothero@users.noreply.github.com> Date: Sat, 30 Sep 2023 20:53:14 -0400 Subject: [PATCH 1/5] replaces custom pack mod with starknet StorePacking (#373) * StorePacking simplifies project and increases gas efficiency --- .github/workflows/build.yml | 14 - contracts/adventurer/Scarb.toml | 1 - contracts/adventurer/src/adventurer.cairo | 223 ++++----- .../adventurer/src/adventurer_meta.cairo | 62 +-- .../adventurer/src/adventurer_stats.cairo | 118 ++--- .../adventurer/src/adventurer_utils.cairo | 68 ++- contracts/adventurer/src/bag.cairo | 110 ++--- contracts/adventurer/src/item_meta.cairo | 194 ++++---- contracts/adventurer/src/item_primitive.cairo | 43 +- contracts/game/src/game/game_entropy.cairo | 35 +- contracts/game/src/lib.cairo | 63 ++- contracts/loot/Scarb.toml | 1 - contracts/loot/src/loot.cairo | 70 ++- contracts/market/src/market.cairo | 13 +- contracts/pack/.gitignore | 1 - contracts/pack/Scarb.toml | 8 - contracts/pack/src/constants.cairo | 435 ------------------ contracts/pack/src/lib.cairo | 2 - contracts/pack/src/pack.cairo | 52 --- 19 files changed, 455 insertions(+), 1058 deletions(-) delete mode 100644 contracts/pack/.gitignore delete mode 100644 contracts/pack/Scarb.toml delete mode 100644 contracts/pack/src/constants.cairo delete mode 100644 contracts/pack/src/lib.cairo delete mode 100644 contracts/pack/src/pack.cairo diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7a287b1f4..67070cfed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,20 +66,6 @@ jobs: run: | cd contracts/market && scarb build && scarb cairo-test - build-pack: - name: Build Pack - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Setup Scarb - run: | - curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | bash -s -- -v ${{ env.SCARB_VERSION }} - - - name: Scarb build - run: | - cd contracts/pack && scarb build && scarb cairo-test - build-obstacles: name: Build Obstacles runs-on: ubuntu-latest diff --git a/contracts/adventurer/Scarb.toml b/contracts/adventurer/Scarb.toml index c3067f82f..b245dd882 100644 --- a/contracts/adventurer/Scarb.toml +++ b/contracts/adventurer/Scarb.toml @@ -5,7 +5,6 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -pack = { path = "../pack" } lootitems = { path = "../loot" } obstacles = { path = "../obstacles" } combat = { path = "../combat" } diff --git a/contracts/adventurer/src/adventurer.cairo b/contracts/adventurer/src/adventurer.cairo index 9b4e269ee..0e4414141 100644 --- a/contracts/adventurer/src/adventurer.cairo +++ b/contracts/adventurer/src/adventurer.cairo @@ -1,4 +1,7 @@ +use starknet::{StorePacking}; use core::result::ResultTrait; +use core::integer::u256_try_as_non_zero; +use zeroable::NonZeroIntoImpl; use integer::{u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub}; use traits::{TryInto, Into}; use option::OptionTrait; @@ -6,9 +9,9 @@ use poseidon::poseidon_hash_span; use array::ArrayTrait; use super::{ - item_meta::{ItemSpecials, ItemSpecialsStorage, ImplItemSpecials}, adventurer_stats::Stats, - item_primitive::ItemPrimitive, adventurer_utils::{AdventurerUtils}, exploration::ExploreUtils, - bag::{Bag, IBag, ImplBag}, + item_meta::{ItemSpecials, ItemSpecialsStorage, ImplItemSpecials}, + adventurer_stats::{Stats, StatsPacking}, item_primitive::{ItemPrimitive, ItemPrimitivePacking}, + adventurer_utils::{AdventurerUtils}, exploration::ExploreUtils, bag::{Bag, IBag, ImplBag}, constants::{ adventurer_constants::{ STARTING_GOLD, StatisticIndex, POTION_PRICE, STARTING_HEALTH, CHARISMA_POTION_DISCOUNT, @@ -20,15 +23,12 @@ use super::{ JEWELRY_BONUS_BEAST_GOLD_PERCENT, JEWELRY_BONUS_CRITICAL_HIT_PERCENT_PER_GREATNESS, JEWELRY_BONUS_NAME_MATCH_PERCENT_PER_GREATNESS, NECKLACE_ARMOR_BONUS, MINIMUM_DAMAGE_FROM_BEASTS, OBSTACLE_CRITICAL_HIT_CHANCE, BEAST_CRITICAL_HIT_CHANCE, - SILVER_RING_LUCK_BONUS_PER_GREATNESS, MINIMUM_DAMAGE_FROM_OBSTACLES, MINIMUM_DAMAGE_TO_BEASTS + SILVER_RING_LUCK_BONUS_PER_GREATNESS, MINIMUM_DAMAGE_FROM_OBSTACLES, + MINIMUM_DAMAGE_TO_BEASTS }, discovery_constants::DiscoveryEnums::{ExploreResult, DiscoveryType} } }; -use pack::{ - pack::{Packing, rshift_split}, constants, - constants::{MASK_16, pow, MASK_8, MASK_3, MASK_BOOL, mask, U128_MASK_8, u128_pow} -}; use lootitems::{ loot::{Loot, ILoot, ImplLoot}, constants::{ItemSuffix, ItemId, NamePrefixLength, NameSuffixLength} @@ -60,71 +60,89 @@ struct Adventurer { mutated: bool, // not packed } -impl AdventurerPacking of Packing { - fn pack(self: Adventurer) -> felt252 { - (self.last_action.into() - + self.health.into() * pow::TWO_POW_9 - + self.xp.into() * pow::TWO_POW_18 - + self.stats.pack().into() * pow::TWO_POW_31 - + self.gold.into() * pow::TWO_POW_61 - + self.weapon.pack().into() * pow::TWO_POW_70 - + self.chest.pack().into() * pow::TWO_POW_91 - + self.head.pack().into() * pow::TWO_POW_112 - + self.waist.pack().into() * pow::TWO_POW_133 - + self.foot.pack().into() * pow::TWO_POW_154 - + self.hand.pack().into() * pow::TWO_POW_175 - + self.neck.pack().into() * pow::TWO_POW_196 - + self.ring.pack().into() * pow::TWO_POW_217 - + self.beast_health.into() * pow::TWO_POW_238 - + self.stat_points_available.into() * pow::TWO_POW_247) +const TWO_POW_3: u256 = 0x8; +const TWO_POW_9: u256 = 0x200; +const TWO_POW_13: u256 = 0x2000; +const TWO_POW_18: u256 = 0x40000; +const TWO_POW_21: u256 = 0x200000; +const TWO_POW_30: u256 = 0x40000000; +const TWO_POW_31: u256 = 0x80000000; +const TWO_POW_61: u256 = 0x2000000000000000; +const TWO_POW_70: u256 = 0x400000000000000000; +const TWO_POW_91: u256 = 0x80000000000000000000000; +const TWO_POW_112: u256 = 0x10000000000000000000000000000; +const TWO_POW_133: u256 = 0x2000000000000000000000000000000000; +const TWO_POW_154: u256 = 0x400000000000000000000000000000000000000; +const TWO_POW_175: u256 = 0x80000000000000000000000000000000000000000000; +const TWO_POW_196: u256 = 0x10000000000000000000000000000000000000000000000000; +const TWO_POW_217: u256 = 0x2000000000000000000000000000000000000000000000000000000; +const TWO_POW_238: u256 = 0x400000000000000000000000000000000000000000000000000000000000; +const TWO_POW_247: u256 = 0x80000000000000000000000000000000000000000000000000000000000000; + +impl AdventurerPacking of StorePacking { + fn pack(value: Adventurer) -> felt252 { + (value.last_action.into() + + value.health.into() * TWO_POW_9 + + value.xp.into() * TWO_POW_18 + + StatsPacking::pack(value.stats).into() * TWO_POW_31 + + value.gold.into() * TWO_POW_61 + + ItemPrimitivePacking::pack(value.weapon).into() * TWO_POW_70 + + ItemPrimitivePacking::pack(value.chest).into() * TWO_POW_91 + + ItemPrimitivePacking::pack(value.head).into() * TWO_POW_112 + + ItemPrimitivePacking::pack(value.waist).into() * TWO_POW_133 + + ItemPrimitivePacking::pack(value.foot).into() * TWO_POW_154 + + ItemPrimitivePacking::pack(value.hand).into() * TWO_POW_175 + + ItemPrimitivePacking::pack(value.neck).into() * TWO_POW_196 + + ItemPrimitivePacking::pack(value.ring).into() * TWO_POW_217 + + value.beast_health.into() * TWO_POW_238 + + value.stat_points_available.into() * TWO_POW_247) .try_into() - .expect('pack Adventurer') - } - - fn unpack(packed: felt252) -> Adventurer { - let packed = packed.into(); - let (packed, last_action) = rshift_split(packed, pow::TWO_POW_9); - let (packed, health) = rshift_split(packed, pow::TWO_POW_9); - let (packed, xp) = rshift_split(packed, pow::TWO_POW_13); - let (packed, stats) = rshift_split(packed, pow::TWO_POW_30); - let (packed, gold) = rshift_split(packed, pow::TWO_POW_9); - let (packed, weapon) = rshift_split(packed, pow::TWO_POW_21); - let (packed, chest) = rshift_split(packed, pow::TWO_POW_21); - let (packed, head) = rshift_split(packed, pow::TWO_POW_21); - let (packed, waist) = rshift_split(packed, pow::TWO_POW_21); - let (packed, foot) = rshift_split(packed, pow::TWO_POW_21); - let (packed, hand) = rshift_split(packed, pow::TWO_POW_21); - let (packed, neck) = rshift_split(packed, pow::TWO_POW_21); - let (packed, ring) = rshift_split(packed, pow::TWO_POW_21); - let (packed, beast_health) = rshift_split(packed, pow::TWO_POW_9); - let (_, stat_points_available) = rshift_split(packed, pow::TWO_POW_3); + .unwrap() + } + + fn unpack(value: felt252) -> Adventurer { + let packed = value.into(); + let (packed, last_action) = integer::U256DivRem::div_rem( + packed, TWO_POW_9.try_into().unwrap() + ); + let (packed, health) = integer::U256DivRem::div_rem(packed, TWO_POW_9.try_into().unwrap()); + let (packed, xp) = integer::U256DivRem::div_rem(packed, TWO_POW_13.try_into().unwrap()); + let (packed, stats) = integer::U256DivRem::div_rem(packed, TWO_POW_30.try_into().unwrap()); + let (packed, gold) = integer::U256DivRem::div_rem(packed, TWO_POW_9.try_into().unwrap()); + let (packed, weapon) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, chest) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, head) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, waist) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, foot) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, hand) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, neck) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, ring) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, beast_health) = integer::U256DivRem::div_rem( + packed, TWO_POW_9.try_into().unwrap() + ); + let (_, stat_points_available) = integer::U256DivRem::div_rem( + packed, TWO_POW_3.try_into().unwrap() + ); Adventurer { - last_action: last_action.try_into().expect('unpack Adventurer last_action'), - health: health.try_into().expect('unpack Adventurer health'), - xp: xp.try_into().expect('unpack Adventurer xp'), - stats: Packing::unpack(stats.try_into().expect('unpack Adventurer stats')), - gold: gold.try_into().expect('unpack Adventurer gold'), - weapon: Packing::unpack(weapon.try_into().expect('unpack Adventurer weapon')), - chest: Packing::unpack(chest.try_into().expect('unpack Adventurer chest')), - head: Packing::unpack(head.try_into().expect('unpack Adventurer head')), - waist: Packing::unpack(waist.try_into().expect('unpack Adventurer waist')), - foot: Packing::unpack(foot.try_into().expect('unpack Adventurer foot')), - hand: Packing::unpack(hand.try_into().expect('unpack Adventurer hand')), - neck: Packing::unpack(neck.try_into().expect('unpack Adventurer neck')), - ring: Packing::unpack(ring.try_into().expect('unpack Adventurer ring')), - beast_health: beast_health.try_into().expect('unpack Adventurer beast_health'), - stat_points_available: stat_points_available - .try_into() - .expect('unpack Adventurer stat_upgrade'), + last_action: last_action.try_into().unwrap(), + health: health.try_into().unwrap(), + xp: xp.try_into().unwrap(), + stats: StatsPacking::unpack(stats.try_into().unwrap()), + gold: gold.try_into().unwrap(), + weapon: ItemPrimitivePacking::unpack(weapon.try_into().unwrap()), + chest: ItemPrimitivePacking::unpack(chest.try_into().unwrap()), + head: ItemPrimitivePacking::unpack(head.try_into().unwrap()), + waist: ItemPrimitivePacking::unpack(waist.try_into().unwrap()), + foot: ItemPrimitivePacking::unpack(foot.try_into().unwrap()), + hand: ItemPrimitivePacking::unpack(hand.try_into().unwrap()), + neck: ItemPrimitivePacking::unpack(neck.try_into().unwrap()), + ring: ItemPrimitivePacking::unpack(ring.try_into().unwrap()), + beast_health: beast_health.try_into().unwrap(), + stat_points_available: stat_points_available.try_into().unwrap(), mutated: false, } } - - // TODO: add overflow pack protection - fn overflow_pack_protection(self: Adventurer) -> Adventurer { - self - } } #[generate_trait] @@ -967,7 +985,7 @@ impl ImplAdventurer of IAdventurer { hash_span.append(self.xp.into()); hash_span.append(adventurer_entropy.into()); let poseidon = poseidon_hash_span(hash_span.span()); - let (d, r) = rshift_split(poseidon.into(), 340282366920938463463374607431768211455); + let (d, r) = integer::U256DivRem::div_rem(poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap()); r.try_into().unwrap() } else { 0 @@ -1414,7 +1432,7 @@ impl ImplAdventurer of IAdventurer { hash_span.append(game_entropy.into()); let poseidon = poseidon_hash_span(hash_span.span()); - let (d, r) = rshift_split(poseidon.into(), U128_MAX.into()); + let (d, r) = integer::U256DivRem::div_rem(poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap()); return (r.try_into().unwrap(), d.try_into().unwrap()); } @@ -1594,7 +1612,8 @@ impl ImplAdventurer of IAdventurer { .jewelry_armor_bonus(armor_details.item_type, combat_result.base_armor); // adjust damage for jewelry armor bonus - if combat_result.total_damage > (jewelry_armor_bonus + MINIMUM_DAMAGE_FROM_OBSTACLES.into()) { + if combat_result + .total_damage > (jewelry_armor_bonus + MINIMUM_DAMAGE_FROM_OBSTACLES.into()) { combat_result.total_damage -= jewelry_armor_bonus; } else { combat_result.total_damage = MINIMUM_DAMAGE_FROM_OBSTACLES.into(); @@ -1691,7 +1710,7 @@ mod tests { use combat::{constants::CombatEnums::{Slot, Type}}; use beasts::{beast::{ImplBeast, Beast}, constants::BeastSettings}; use survivor::{ - adventurer::{IAdventurer, ImplAdventurer, Adventurer}, + adventurer::{IAdventurer, ImplAdventurer, Adventurer, AdventurerPacking}, item_meta::{ItemSpecials, ItemSpecialsStorage, ImplItemSpecials}, adventurer_stats::Stats, item_primitive::ItemPrimitive, adventurer_utils::{AdventurerUtils}, bag::{Bag, ImplBag}, constants::{ @@ -1707,9 +1726,6 @@ mod tests { discovery_constants::DiscoveryEnums::{ExploreResult, DiscoveryType} } }; - use pack::{ - pack::{Packing, rshift_split}, constants, constants::{MASK_8, pow, MASK_3, MASK_BOOL, mask} - }; #[test] #[available_gas(505770)] @@ -2736,8 +2752,8 @@ mod tests { stat_points_available: 7, mutated: false }; - let packed = adventurer.pack(); - let unpacked: Adventurer = Packing::unpack(packed); + let packed = AdventurerPacking::pack(adventurer); + let unpacked: Adventurer = AdventurerPacking::unpack(packed); assert(adventurer.last_action == unpacked.last_action, 'last_action'); assert(adventurer.health == unpacked.health, 'health'); assert(adventurer.xp == unpacked.xp, 'xp'); @@ -2778,59 +2794,12 @@ mod tests { 'stat_points_available' ); } - - #[test] - #[available_gas(3000000)] - fn test_packing_stat_overflow_protection() { - // create an adventurer with stats at max u8 - let adventurer = Adventurer { - last_action: 511, - health: 511, - xp: 8191, - stats: Stats { - strength: 255, - dexterity: 255, - vitality: 255, - intelligence: 255, - wisdom: 255, - charisma: 255, - luck: 255 - }, - gold: 511, - weapon: ItemPrimitive { id: 127, xp: 511, metadata: 31, }, - chest: ItemPrimitive { id: 1, xp: 0, metadata: 0, }, - head: ItemPrimitive { id: 127, xp: 511, metadata: 31, }, - waist: ItemPrimitive { id: 87, xp: 511, metadata: 4, }, - foot: ItemPrimitive { id: 78, xp: 511, metadata: 5, }, - hand: ItemPrimitive { id: 34, xp: 511, metadata: 6, }, - neck: ItemPrimitive { id: 32, xp: 511, metadata: 7, }, - ring: ItemPrimitive { id: 1, xp: 511, metadata: 8, }, - beast_health: 511, - stat_points_available: 7, - mutated: false - }; - - // pack adventurer - let packed = adventurer.pack(); - - // unpack adventurer - let unpacked: Adventurer = Packing::unpack(packed); - - // verify packing function didn't overflow stats - // but instead set values to max - assert(unpacked.stats.strength == MAX_STAT_VALUE, 'strength'); - assert(unpacked.stats.dexterity == MAX_STAT_VALUE, 'dexterity'); - assert(unpacked.stats.vitality == MAX_STAT_VALUE, 'vitality'); - assert(unpacked.stats.intelligence == MAX_STAT_VALUE, 'intelligence'); - assert(unpacked.stats.wisdom == MAX_STAT_VALUE, 'wisdom'); - assert(unpacked.stats.charisma == MAX_STAT_VALUE, 'charisma'); - } - + #[test] #[available_gas(2000000)] fn test_new_adventurer() { let mut adventurer = ImplAdventurer::new(12, 0, 0, 0); - adventurer.pack(); + AdventurerPacking::pack(adventurer); assert(adventurer.health == STARTING_HEALTH, 'wrong starting health'); assert(adventurer.gold == STARTING_GOLD, 'wrong starting gold'); assert(adventurer.xp == 0, 'wrong starting xp'); @@ -2882,7 +2851,7 @@ mod tests { assert(adventurer.gold == MAX_GOLD, 'gold should be max'); // pack and unpack adventurer to test overflow in packing - let unpacked: Adventurer = Packing::unpack(adventurer.pack()); + let unpacked: Adventurer = AdventurerPacking::unpack(AdventurerPacking::pack(adventurer)); assert(unpacked.gold == MAX_GOLD, 'should still be max gold'); // extreme/overflow case @@ -2974,7 +2943,7 @@ mod tests { assert(adventurer.stat_points_available == MAX_STAT_UPGRADES, 'stat points should be max'); // pack and unpack at max value to ensure our max values are correct for packing - let unpacked: Adventurer = Packing::unpack(adventurer.pack()); + let unpacked: Adventurer = AdventurerPacking::unpack(AdventurerPacking::pack(adventurer)); assert( unpacked.stat_points_available == MAX_STAT_UPGRADES, 'stat point should still be max' ); diff --git a/contracts/adventurer/src/adventurer_meta.cairo b/contracts/adventurer/src/adventurer_meta.cairo index b1041f506..cadab6453 100644 --- a/contracts/adventurer/src/adventurer_meta.cairo +++ b/contracts/adventurer/src/adventurer_meta.cairo @@ -1,6 +1,5 @@ +use starknet::{StorePacking}; use traits::{TryInto, Into}; -use pack::constants::pow; -use pack::pack::{Packing, rshift_split}; #[derive(Drop, Copy, Serde)] struct AdventurerMetadata { @@ -8,40 +7,41 @@ struct AdventurerMetadata { entropy: u128, } -impl PackingAdventurerMetadata of Packing { - fn pack(self: AdventurerMetadata) -> felt252 { - (self.entropy.into() - + self.name.into() * pow::TWO_POW_128) - .try_into() - .expect('pack AdventurerMetadata') - } - fn unpack(packed: felt252) -> AdventurerMetadata { - let packed = packed.into(); - let (packed, entropy) = rshift_split(packed, pow::TWO_POW_128); - let (_, name) = rshift_split(packed, pow::TWO_POW_128); - AdventurerMetadata { - name: name.try_into().expect('unpack AdvMetadata name'), - entropy: entropy.try_into().expect('unpack AdvMetadata entropy') - } - } +const TWO_POW_128: u256 = 0x100000000000000000000000000000000; - // TODO: add overflow pack protection - fn overflow_pack_protection(self: AdventurerMetadata) -> AdventurerMetadata { - self +impl PackingAdventurerMetadata of StorePacking { + fn pack(value: AdventurerMetadata) -> felt252 { + (value.entropy.into() + value.name.into() * TWO_POW_128).try_into().unwrap() + } + fn unpack(value: felt252) -> AdventurerMetadata { + let packed = value.into(); + let (packed, entropy) = integer::U256DivRem::div_rem( + packed, TWO_POW_128.try_into().unwrap() + ); + let (_, name) = integer::U256DivRem::div_rem(packed, TWO_POW_128.try_into().unwrap()); + AdventurerMetadata { name: name.try_into().unwrap(), entropy: entropy.try_into().unwrap() } } } #[cfg(test)] #[test] -#[available_gas(96380)] +#[available_gas(116600)] fn test_pack_unpack_adventurer_meta() { - let meta = AdventurerMetadata { - name: 'abcdefghijklmno', - entropy: 340282366920938463463374607431768211455 - }; + // max value case + let max_u128 = 340282366920938463463374607431768211455; + let name_length = 'abcdefghijklmno'; - let packed = meta.pack(); - let unpacked: AdventurerMetadata = Packing::unpack(packed); - assert(meta.name == unpacked.name, 'name'); - assert(meta.entropy == unpacked.entropy, 'entropy'); -} + let meta = AdventurerMetadata { name: name_length, entropy: max_u128 }; + + let packed = PackingAdventurerMetadata::pack(meta); + let unpacked: AdventurerMetadata = PackingAdventurerMetadata::unpack(packed); + assert(meta.name == unpacked.name, 'name should be max'); + assert(meta.entropy == unpacked.entropy, 'entropy should be max u128'); + + // zero case + let meta = AdventurerMetadata { name: 0, entropy: 0 }; + let packed = PackingAdventurerMetadata::pack(meta); + let unpacked: AdventurerMetadata = PackingAdventurerMetadata::unpack(packed); + assert(unpacked.name == 0, 'name should be 0'); + assert(unpacked.entropy == 0, 'entropy should be 0'); +} \ No newline at end of file diff --git a/contracts/adventurer/src/adventurer_stats.cairo b/contracts/adventurer/src/adventurer_stats.cairo index 510c51053..07bd7dc6b 100644 --- a/contracts/adventurer/src/adventurer_stats.cairo +++ b/contracts/adventurer/src/adventurer_stats.cairo @@ -1,6 +1,6 @@ +use starknet::{StorePacking}; use option::OptionTrait; use traits::{TryInto, Into}; -use pack::{pack::{Packing, rshift_split}, constants::pow}; use survivor::constants::adventurer_constants::MAX_STAT_VALUE; #[derive(Drop, Copy, Serde)] @@ -14,7 +14,7 @@ struct Stats { // 5 bits each wisdom: u8, // 5 bits charisma: u8, // 5 bits // Metaphysical - luck: u8 // dynamically generated (not stored) + luck: u8 // // not stored - dynamically generated } #[generate_trait] @@ -26,64 +26,51 @@ impl StatUtils of IStat { } } -impl StatsPacking of Packing { - fn pack(self: Stats) -> felt252 { - let overflow_protected = self.overflow_pack_protection(); - - (overflow_protected.strength.into() - + overflow_protected.dexterity.into() * pow::TWO_POW_5 - + overflow_protected.vitality.into() * pow::TWO_POW_10 - + overflow_protected.intelligence.into() * pow::TWO_POW_15 - + overflow_protected.wisdom.into() * pow::TWO_POW_20 - + overflow_protected.charisma.into() * pow::TWO_POW_25) +const TWO_POW_5: u256 = 0x20; +const TWO_POW_10: u256 = 0x400; +const TWO_POW_15: u256 = 0x8000; +const TWO_POW_20: u256 = 0x100000; +const TWO_POW_25: u256 = 0x2000000; + +impl StatsPacking of StorePacking { + fn pack(value: Stats) -> felt252 { + (value.strength.into() + + value.dexterity.into() * TWO_POW_5 + + value.vitality.into() * TWO_POW_10 + + value.intelligence.into() * TWO_POW_15 + + value.wisdom.into() * TWO_POW_20 + + value.charisma.into() * TWO_POW_25) .try_into() - .expect('pack Stats') + .unwrap() } - fn unpack(packed: felt252) -> Stats { - let packed = packed.into(); - let (packed, strength) = rshift_split(packed, pow::TWO_POW_5); - let (packed, dexterity) = rshift_split(packed, pow::TWO_POW_5); - let (packed, vitality) = rshift_split(packed, pow::TWO_POW_5); - let (packed, intelligence) = rshift_split(packed, pow::TWO_POW_5); - let (packed, wisdom) = rshift_split(packed, pow::TWO_POW_5); - let (_, charisma) = rshift_split(packed, pow::TWO_POW_5); + fn unpack(value: felt252) -> Stats { + let packed = value.into(); + let (packed, strength) = integer::U256DivRem::div_rem( + packed, TWO_POW_5.try_into().unwrap() + ); + let (packed, dexterity) = integer::U256DivRem::div_rem( + packed, TWO_POW_5.try_into().unwrap() + ); + let (packed, vitality) = integer::U256DivRem::div_rem( + packed, TWO_POW_5.try_into().unwrap() + ); + let (packed, intelligence) = integer::U256DivRem::div_rem( + packed, TWO_POW_5.try_into().unwrap() + ); + let (packed, wisdom) = integer::U256DivRem::div_rem(packed, TWO_POW_5.try_into().unwrap()); + let (_, charisma) = integer::U256DivRem::div_rem(packed, TWO_POW_5.try_into().unwrap()); Stats { - strength: strength.try_into().expect('unpack Stats strength'), - dexterity: dexterity.try_into().expect('unpack Stats dexterity'), - vitality: vitality.try_into().expect('unpack Stats vitality'), - intelligence: intelligence.try_into().expect('unpack Stats intelligence'), - wisdom: wisdom.try_into().expect('unpack Stats wisdom'), - charisma: charisma.try_into().expect('unpack Stats charisma'), + strength: strength.try_into().unwrap(), + dexterity: dexterity.try_into().unwrap(), + vitality: vitality.try_into().unwrap(), + intelligence: intelligence.try_into().unwrap(), + wisdom: wisdom.try_into().unwrap(), + charisma: charisma.try_into().unwrap(), luck: 0 } } - - fn overflow_pack_protection(self: Stats) -> Stats { - let mut overflow_protected_stats = self; - - if self.strength > MAX_STAT_VALUE { - overflow_protected_stats.strength = MAX_STAT_VALUE; - }; - if self.dexterity > MAX_STAT_VALUE { - overflow_protected_stats.dexterity = MAX_STAT_VALUE; - } - if self.vitality > MAX_STAT_VALUE { - overflow_protected_stats.vitality = MAX_STAT_VALUE; - } - if self.intelligence > MAX_STAT_VALUE { - overflow_protected_stats.intelligence = MAX_STAT_VALUE; - } - if self.wisdom > MAX_STAT_VALUE { - overflow_protected_stats.wisdom = MAX_STAT_VALUE; - } - if self.charisma > MAX_STAT_VALUE { - overflow_protected_stats.charisma = MAX_STAT_VALUE; - } - - overflow_protected_stats - } } // --------------------------- @@ -103,7 +90,7 @@ mod tests { strength: 0, dexterity: 0, vitality: 0, intelligence: 0, wisdom: 0, charisma: 0, luck: 0 }; - let packed = stats.pack(); + let packed = StatsPacking::pack(stats); let unpacked = StatsPacking::unpack(packed); assert(stats.strength == unpacked.strength, 'strength zero case'); assert(stats.dexterity == unpacked.dexterity, 'dexterity zero case'); @@ -124,7 +111,7 @@ mod tests { luck: 31 }; - let packed = stats.pack(); + let packed = StatsPacking::pack(stats); let unpacked = StatsPacking::unpack(packed); assert(stats.strength == unpacked.strength, 'strength storage limit'); assert(stats.dexterity == unpacked.dexterity, 'dexterity storage limit'); @@ -133,28 +120,5 @@ mod tests { assert(stats.wisdom == unpacked.wisdom, 'wisdom storage limit'); assert(stats.charisma == unpacked.charisma, 'charisma storage limit'); assert(unpacked.luck == 0, 'luck is zero from storage'); - - // overflow storage limit using max u8 - let stats = Stats { - strength: 255, - dexterity: 255, - vitality: 255, - intelligence: 255, - wisdom: 255, - charisma: 255, - luck: 255 - }; - - let packed = stats.pack(); - let unpacked = StatsPacking::unpack(packed); - - // assert packing function prevented overflow - assert(unpacked.strength == MAX_STAT_VALUE, 'strength pack overflow'); - assert(unpacked.dexterity == MAX_STAT_VALUE, 'dexterity pack overflow'); - assert(unpacked.vitality == MAX_STAT_VALUE, 'vitality pack overflow'); - assert(unpacked.intelligence == MAX_STAT_VALUE, 'intelligence pack overflow'); - assert(unpacked.wisdom == MAX_STAT_VALUE, 'wisdom pack overflow'); - assert(unpacked.charisma == MAX_STAT_VALUE, 'charisma pack overflow'); - assert(unpacked.luck == 0, 'luck is zero from storage'); } } diff --git a/contracts/adventurer/src/adventurer_utils.cairo b/contracts/adventurer/src/adventurer_utils.cairo index 39b8eae47..72745d736 100644 --- a/contracts/adventurer/src/adventurer_utils.cairo +++ b/contracts/adventurer/src/adventurer_utils.cairo @@ -3,7 +3,9 @@ use core::{result::ResultTrait, traits::{TryInto, Into}}; use poseidon::poseidon_hash_span; use option::OptionTrait; use array::ArrayTrait; -use integer::{u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, U128IntoU256}; +use integer::{ + u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, U128IntoU256, u256_try_as_non_zero +}; use super::{ constants::{ adventurer_constants::{ @@ -23,10 +25,6 @@ use lootitems::constants::{ } }; use combat::constants::CombatEnums::{Type, Tier, Slot}; -use pack::{ - pack::{rshift_split}, - constants::{MASK_16, pow, MASK_8, MASK_3, MASK_BOOL, mask, U128_MASK_8, u128_pow} -}; #[generate_trait] impl AdventurerUtils of IAdventurerUtils { @@ -94,7 +92,9 @@ impl AdventurerUtils of IAdventurerUtils { hash_span.append(block_number.into()); hash_span.append(block_timestamp.into()); let poseidon: felt252 = poseidon_hash_span(hash_span.span()).into(); - let (d, r) = rshift_split(poseidon.into(), U128_MAX.into()); + let (d, r) = integer::U256DivRem::div_rem( + poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); r.try_into().unwrap() } @@ -107,7 +107,9 @@ impl AdventurerUtils of IAdventurerUtils { hash_span.append(entropy.into()); hash_span.append(item_id.into()); let poseidon: felt252 = poseidon_hash_span(hash_span.span()).into(); - let (d, r) = rshift_split(poseidon.into(), U128_MAX.into()); + let (d, r) = integer::U256DivRem::div_rem( + poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); (r.try_into().unwrap(), d.try_into().unwrap()) } @@ -219,7 +221,9 @@ impl AdventurerUtils of IAdventurerUtils { // @param felt_to_split: felt to split // @return (u128, u128): tuple of u128s fn split_hash(felt_to_split: felt252) -> (u128, u128) { - let (d, r) = rshift_split(felt_to_split.into(), U128_MAX.into()); + let (d, r) = integer::U256DivRem::div_rem( + felt_to_split.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); (r.try_into().unwrap(), d.try_into().unwrap()) } @@ -270,25 +274,41 @@ impl AdventurerUtils of IAdventurerUtils { fn u128_to_u8_array(value: u128) -> Array { let mut result = ArrayTrait::::new(); - result.append((value & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_8) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_16) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_24) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_32) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_40) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_48) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_56) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_64) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_72) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_80) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_88) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_96) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_104) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_112) & U128_MASK_8).try_into().unwrap()); - result.append(((value / u128_pow::_120) & U128_MASK_8).try_into().unwrap()); + result.append((value & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_8) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_16) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_24) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_32) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_40) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_48) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_56) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_64) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_72) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_80) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_88) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_96) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_104) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_112) & MASK_8).try_into().unwrap()); + result.append(((value / TWO_POW_120) & MASK_8).try_into().unwrap()); result } } +const MASK_8: u128 = 0xFF; +const TWO_POW_8: u128 = 0x100; +const TWO_POW_16: u128 = 0x10000; +const TWO_POW_24: u128 = 0x1000000; +const TWO_POW_32: u128 = 0x100000000; +const TWO_POW_40: u128 = 0x10000000000; +const TWO_POW_48: u128 = 0x1000000000000; +const TWO_POW_56: u128 = 0x100000000000000; +const TWO_POW_64: u128 = 0x10000000000000000; +const TWO_POW_72: u128 = 0x1000000000000000000; +const TWO_POW_80: u128 = 0x100000000000000000000; +const TWO_POW_88: u128 = 0x10000000000000000000000; +const TWO_POW_96: u128 = 0x1000000000000000000000000; +const TWO_POW_104: u128 = 0x100000000000000000000000000; +const TWO_POW_112: u128 = 0x10000000000000000000000000000; +const TWO_POW_120: u128 = 0x1000000000000000000000000000000; // --------------------------- // ---------- Tests ---------- diff --git a/contracts/adventurer/src/bag.cairo b/contracts/adventurer/src/bag.cairo index 08c3b5da8..b9623c387 100644 --- a/contracts/adventurer/src/bag.cairo +++ b/contracts/adventurer/src/bag.cairo @@ -1,11 +1,10 @@ -use traits::{TryInto, Into}; -use option::OptionTrait; -use pack::{pack::{Packing, rshift_split}, constants::pow}; +use starknet::{StorePacking}; +use lootitems::constants::ItemId; use super::{ - adventurer::{Adventurer, ImplAdventurer, IAdventurer}, - item_primitive::{ItemPrimitive, ImplItemPrimitive}, item_meta::{ImplItemSpecials, IItemSpecials} + adventurer::{Adventurer, ImplAdventurer}, + item_primitive::{ItemPrimitive, ImplItemPrimitive, ItemPrimitivePacking}, + item_meta::{ImplItemSpecials} }; -use lootitems::constants::ItemId; // Bag is used for storing gear not equipped to the adventurer // TODO: Change this to an Array with id: u8, size: u8, and modified: bool @@ -26,57 +25,65 @@ struct Bag { mutated: bool, } -impl BagPacking of Packing { - fn pack(self: Bag) -> felt252 { - (self.item_1.pack().into() - + self.item_2.pack().into() * pow::TWO_POW_21 - + self.item_3.pack().into() * pow::TWO_POW_42 - + self.item_4.pack().into() * pow::TWO_POW_63 - + self.item_5.pack().into() * pow::TWO_POW_84 - + self.item_6.pack().into() * pow::TWO_POW_105 - + self.item_7.pack().into() * pow::TWO_POW_126 - + self.item_8.pack().into() * pow::TWO_POW_147 - + self.item_9.pack().into() * pow::TWO_POW_168 - + self.item_10.pack().into() * pow::TWO_POW_189 - + self.item_11.pack().into() * pow::TWO_POW_210) +const TWO_POW_21: u256 = 0x200000; +const TWO_POW_42: u256 = 0x40000000000; +const TWO_POW_63: u256 = 0x8000000000000000; +const TWO_POW_84: u256 = 0x1000000000000000000000; +const TWO_POW_105: u256 = 0x200000000000000000000000000; +const TWO_POW_126: u256 = 0x40000000000000000000000000000000; +const TWO_POW_147: u256 = 0x8000000000000000000000000000000000000; +const TWO_POW_168: u256 = 0x1000000000000000000000000000000000000000000; +const TWO_POW_189: u256 = 0x200000000000000000000000000000000000000000000000; +const TWO_POW_210: u256 = 0x40000000000000000000000000000000000000000000000000000; + +impl BagPacking of StorePacking { + fn pack(value: Bag) -> felt252 { + (ItemPrimitivePacking::pack(value.item_1).into() + + ItemPrimitivePacking::pack(value.item_2).into() * TWO_POW_21 + + ItemPrimitivePacking::pack(value.item_3).into() * TWO_POW_42 + + ItemPrimitivePacking::pack(value.item_4).into() * TWO_POW_63 + + ItemPrimitivePacking::pack(value.item_5).into() * TWO_POW_84 + + ItemPrimitivePacking::pack(value.item_6).into() * TWO_POW_105 + + ItemPrimitivePacking::pack(value.item_7).into() * TWO_POW_126 + + ItemPrimitivePacking::pack(value.item_8).into() * TWO_POW_147 + + ItemPrimitivePacking::pack(value.item_9).into() * TWO_POW_168 + + ItemPrimitivePacking::pack(value.item_10).into() * TWO_POW_189 + + ItemPrimitivePacking::pack(value.item_11).into() * TWO_POW_210) .try_into() - .expect('pack Bag') + .unwrap() } - fn unpack(packed: felt252) -> Bag { - let packed = packed.into(); - let (packed, item_1) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_2) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_3) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_4) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_5) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_6) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_7) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_8) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_9) = rshift_split(packed, pow::TWO_POW_21); - let (packed, item_10) = rshift_split(packed, pow::TWO_POW_21); - let (_, item_11) = rshift_split(packed, pow::TWO_POW_21); + fn unpack(value: felt252) -> Bag { + let packed = value.into(); + let (packed, item_1) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_2) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_3) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_4) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_5) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_6) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_7) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_8) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_9) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); + let (packed, item_10) = integer::U256DivRem::div_rem( + packed, TWO_POW_21.try_into().unwrap() + ); + let (_, item_11) = integer::U256DivRem::div_rem(packed, TWO_POW_21.try_into().unwrap()); Bag { - item_1: Packing::unpack(item_1.try_into().expect('unpack Bag item_1')), - item_2: Packing::unpack(item_2.try_into().expect('unpack Bag item_2')), - item_3: Packing::unpack(item_3.try_into().expect('unpack Bag item_3')), - item_4: Packing::unpack(item_4.try_into().expect('unpack Bag item_4')), - item_5: Packing::unpack(item_5.try_into().expect('unpack Bag item_5')), - item_6: Packing::unpack(item_6.try_into().expect('unpack Bag item_6')), - item_7: Packing::unpack(item_7.try_into().expect('unpack Bag item_7')), - item_8: Packing::unpack(item_8.try_into().expect('unpack Bag item_8')), - item_9: Packing::unpack(item_9.try_into().expect('unpack Bag item_9')), - item_10: Packing::unpack(item_10.try_into().expect('unpack Bag item_10')), - item_11: Packing::unpack(item_11.try_into().expect('unpack Bag item_11')), + item_1: ItemPrimitivePacking::unpack(item_1.try_into().unwrap()), + item_2: ItemPrimitivePacking::unpack(item_2.try_into().unwrap()), + item_3: ItemPrimitivePacking::unpack(item_3.try_into().unwrap()), + item_4: ItemPrimitivePacking::unpack(item_4.try_into().unwrap()), + item_5: ItemPrimitivePacking::unpack(item_5.try_into().unwrap()), + item_6: ItemPrimitivePacking::unpack(item_6.try_into().unwrap()), + item_7: ItemPrimitivePacking::unpack(item_7.try_into().unwrap()), + item_8: ItemPrimitivePacking::unpack(item_8.try_into().unwrap()), + item_9: ItemPrimitivePacking::unpack(item_9.try_into().unwrap()), + item_10: ItemPrimitivePacking::unpack(item_10.try_into().unwrap()), + item_11: ItemPrimitivePacking::unpack(item_11.try_into().unwrap()), mutated: false } } - - // Not used for bag - fn overflow_pack_protection(self: Bag) -> Bag { - self - } } #[generate_trait] @@ -374,9 +381,8 @@ impl ImplBag of IBag { // --------------------------- #[cfg(test)] mod tests { - use survivor::{bag::{Bag, ImplBag, IBag}, item_primitive::{ItemPrimitive}}; + use survivor::{bag::{Bag, ImplBag, IBag, BagPacking}, item_primitive::{ItemPrimitive}}; use lootitems::{constants::ItemId}; - use pack::{pack::{Packing}}; #[test] #[available_gas(94030)] @@ -613,7 +619,7 @@ mod tests { mutated: false, }; - let packed_bag: Bag = Packing::unpack(bag.pack()); + let packed_bag: Bag = BagPacking::unpack(BagPacking::pack(bag)); assert(packed_bag.item_1.id == 127, 'Loot 1 ID is not 127'); assert(packed_bag.item_1.xp == 511, 'Loot 1 XP is not 511'); diff --git a/contracts/adventurer/src/item_meta.cairo b/contracts/adventurer/src/item_meta.cairo index 87028a39a..68c6add1e 100644 --- a/contracts/adventurer/src/item_meta.cairo +++ b/contracts/adventurer/src/item_meta.cairo @@ -1,4 +1,4 @@ -use pack::{pack::{Packing, rshift_split}, constants::pow}; +use starknet::{StorePacking}; use lootitems::constants::{ItemId, ItemSuffix}; use super::{ adventurer::{Adventurer, IAdventurer, ImplAdventurer}, item_primitive::ItemPrimitive, @@ -61,7 +61,7 @@ struct ItemSpecialsStorage { mutated: bool, } -// TODO: We can greatly simplify and harden our meta data storage by switching to the below +// TODO: Meta data storage can be simplified and more easily extended by meta data storage by switching to the below // data structure. This data structure will allow us to identify the storage id when // it is being operated on and also to flag the storage as modified when it is altered // so that the top-level contract code knows when it needs to write it to storage. @@ -77,22 +77,39 @@ struct ItemSpecialsStorage { // item_specials: Array, // } -impl ItemSpecialsPacking of Packing { - fn pack(self: ItemSpecials) -> felt252 { - let overflow_protected = self.overflow_pack_protection(); - - (overflow_protected.special2.into() - + overflow_protected.special3.into() * pow::TWO_POW_7 - + overflow_protected.special1.into() * pow::TWO_POW_12) +const TWO_POW_4: u256 = 0x10; +const TWO_POW_5: u256 = 0x20; +const TWO_POW_7: u256 = 0x80; +const TWO_POW_12: u256 = 0x1000; +const TWO_POW_16: u256 = 0x10000; // 2^16 +const TWO_POW_32: u256 = 0x100000000; // 2^32 +const TWO_POW_48: u256 = 0x1000000000000; // 2^48 +const TWO_POW_64: u256 = 0x10000000000000000; // 2^64 +const TWO_POW_80: u256 = 0x100000000000000000000; // 2^80 +const TWO_POW_96: u256 = 0x1000000000000000000000000; // 2^96 +const TWO_POW_112: u256 = 0x10000000000000000000000000000; // 2^112 +const TWO_POW_128: u256 = 0x100000000000000000000000000000000; // 2^128 +const TWO_POW_144: u256 = 0x1000000000000000000000000000000000000; // 2^144 + + +impl ItemSpecialsPacking of StorePacking { + fn pack(value: ItemSpecials) -> felt252 { + (value.special2.into() + + value.special3.into() * TWO_POW_7 + + value.special1.into() * TWO_POW_12) .try_into() - .expect('pack ItemSpecials') + .unwrap() } - fn unpack(packed: felt252) -> ItemSpecials { - let packed = packed.into(); - let (packed, special2) = rshift_split(packed, pow::TWO_POW_7); - let (packed, special3) = rshift_split(packed, pow::TWO_POW_5); - let (_, special1) = rshift_split(packed, pow::TWO_POW_4); + fn unpack(value: felt252) -> ItemSpecials { + let packed = value.into(); + let (packed, special2) = integer::U256DivRem::div_rem( + packed, TWO_POW_7.try_into().unwrap() + ); + let (packed, special3) = integer::U256DivRem::div_rem( + packed, TWO_POW_5.try_into().unwrap() + ); + let (_, special1) = integer::U256DivRem::div_rem(packed, TWO_POW_4.try_into().unwrap()); ItemSpecials { special2: special2.try_into().expect('unpack LISN special2'), @@ -100,93 +117,51 @@ impl ItemSpecialsPacking of Packing { special1: special1.try_into().expect('unpack LISN special1') } } - - // @dev This function applies an overflow protection mechanism to the item's specials. - // - // @notice The function receives an instance of ItemSpecials and checks if any of the specials - // exceed their respective max limit values (MAX_SPECIAL1, MAX_SPECIAL2, and MAX_SPECIAL3). - // If a special exceeds its limit, it is reset to the maximum allowable value. - // This way, the function ensures that none of the specials go beyond the predefined limits. - // The function then returns the updated ItemSpecials object. - // - // @param self An instance of ItemSpecials that is to be checked and potentially adjusted for overflow. - // - // @return An instance of ItemSpecials where all the specials are ensured to be within their respective maximum limits. - fn overflow_pack_protection(self: ItemSpecials) -> ItemSpecials { - // Create a mutable copy of self to apply overflow protection - let mut overflow_protected_specials = self; - - // Check if special1 exceeds its max limit - if self.special1 > MAX_SPECIAL1 { - // If special1 overflows, reset it to its max value - overflow_protected_specials.special1 = MAX_SPECIAL1; - }; - - // Check if special2 exceeds its max limit - if self.special2 > MAX_SPECIAL2 { - // If special2 overflows, reset it to its max value - overflow_protected_specials.special2 = MAX_SPECIAL2; - }; - - // Check if special3 exceeds its max limit - if self.special3 > MAX_SPECIAL3 { - // If special3 overflows, reset it to its max value - overflow_protected_specials.special3 = MAX_SPECIAL3; - }; - - // Return the updated ItemSpecials object with overflow protection - overflow_protected_specials - } } -impl ItemSpecialsStoragePacking of Packing { - fn pack(self: ItemSpecialsStorage) -> felt252 { - (self.item_1.pack().into() - + self.item_2.pack().into() * pow::TWO_POW_16 - + self.item_3.pack().into() * pow::TWO_POW_32 - + self.item_4.pack().into() * pow::TWO_POW_48 - + self.item_5.pack().into() * pow::TWO_POW_64 - + self.item_6.pack().into() * pow::TWO_POW_80 - + self.item_7.pack().into() * pow::TWO_POW_96 - + self.item_8.pack().into() * pow::TWO_POW_112 - + self.item_9.pack().into() * pow::TWO_POW_128 - + self.item_10.pack().into() * pow::TWO_POW_144) +impl ItemSpecialsStoragePacking of StorePacking { + fn pack(value: ItemSpecialsStorage) -> felt252 { + (ItemSpecialsPacking::pack(value.item_1).into() + + ItemSpecialsPacking::pack(value.item_2).into() * TWO_POW_16 + + ItemSpecialsPacking::pack(value.item_3).into() * TWO_POW_32 + + ItemSpecialsPacking::pack(value.item_4).into() * TWO_POW_48 + + ItemSpecialsPacking::pack(value.item_5).into() * TWO_POW_64 + + ItemSpecialsPacking::pack(value.item_6).into() * TWO_POW_80 + + ItemSpecialsPacking::pack(value.item_7).into() * TWO_POW_96 + + ItemSpecialsPacking::pack(value.item_8).into() * TWO_POW_112 + + ItemSpecialsPacking::pack(value.item_9).into() * TWO_POW_128 + + ItemSpecialsPacking::pack(value.item_10).into() * TWO_POW_144) .try_into() - .expect('pack LISNS') + .unwrap() } - fn unpack(packed: felt252) -> ItemSpecialsStorage { - let packed = packed.into(); - let (packed, item_1) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_2) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_3) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_4) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_5) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_6) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_7) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_8) = rshift_split(packed, pow::TWO_POW_16); - let (packed, item_9) = rshift_split(packed, pow::TWO_POW_16); - let (_, item_10) = rshift_split(packed, pow::TWO_POW_16); + fn unpack(value: felt252) -> ItemSpecialsStorage { + let packed = value.into(); + let (packed, item_1) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_2) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_3) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_4) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_5) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_6) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_7) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_8) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (packed, item_9) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); + let (_, item_10) = integer::U256DivRem::div_rem(packed, TWO_POW_16.try_into().unwrap()); ItemSpecialsStorage { - item_1: Packing::unpack(item_1.try_into().expect('unpack LISNS item_1')), - item_2: Packing::unpack(item_2.try_into().expect('unpack LISNS item_2')), - item_3: Packing::unpack(item_3.try_into().expect('unpack LISNS item_3')), - item_4: Packing::unpack(item_4.try_into().expect('unpack LISNS item_4')), - item_5: Packing::unpack(item_5.try_into().expect('unpack LISNS item_5')), - item_6: Packing::unpack(item_6.try_into().expect('unpack LISNS item_6')), - item_7: Packing::unpack(item_7.try_into().expect('unpack LISNS item_7')), - item_8: Packing::unpack(item_8.try_into().expect('unpack LISNS item_8')), - item_9: Packing::unpack(item_9.try_into().expect('unpack LISNS item_9')), - item_10: Packing::unpack(item_10.try_into().expect('unpack LISNS item_10')), + item_1: ItemSpecialsPacking::unpack(item_1.try_into().unwrap()), + item_2: ItemSpecialsPacking::unpack(item_2.try_into().unwrap()), + item_3: ItemSpecialsPacking::unpack(item_3.try_into().unwrap()), + item_4: ItemSpecialsPacking::unpack(item_4.try_into().unwrap()), + item_5: ItemSpecialsPacking::unpack(item_5.try_into().unwrap()), + item_6: ItemSpecialsPacking::unpack(item_6.try_into().unwrap()), + item_7: ItemSpecialsPacking::unpack(item_7.try_into().unwrap()), + item_8: ItemSpecialsPacking::unpack(item_8.try_into().unwrap()), + item_9: ItemSpecialsPacking::unpack(item_9.try_into().unwrap()), + item_10: ItemSpecialsPacking::unpack(item_10.try_into().unwrap()), mutated: false, } } - - // TODO: add overflow pack protection - fn overflow_pack_protection(self: ItemSpecialsStorage) -> ItemSpecialsStorage { - self - } } #[generate_trait] @@ -473,14 +448,13 @@ impl ImplItemSpecials of IItemSpecials { // --------------------------- #[cfg(test)] mod tests { - use pack::pack::{Packing}; use lootitems::constants::{ItemId}; use survivor::{ adventurer::{ImplAdventurer}, item_primitive::ItemPrimitive, adventurer_stats::Stats, bag::{Bag, IBag}, item_meta::{ - ImplItemSpecials, ItemSpecialsStorage, ItemSpecials, MAX_SPECIAL1, MAX_SPECIAL2, - MAX_SPECIAL3, STORAGE + ImplItemSpecials, ItemSpecialsStorage, ItemSpecials, ItemSpecialsStoragePacking, + MAX_SPECIAL1, MAX_SPECIAL2, MAX_SPECIAL3, STORAGE }, }; @@ -498,41 +472,31 @@ mod tests { item_4: ItemSpecials { special1: 15, special2: 127, special3: 31 // max packable values }, - item_5: ItemSpecials { special1: 255, special2: 255, special3: 255 // max u8 values - }, - item_6: ItemSpecials { special1: 5, special2: 5, special3: 5 // dnc - }, - item_7: ItemSpecials { special1: 6, special2: 6, special3: 6 // dnc - }, - item_8: ItemSpecials { special1: 7, special2: 7, special3: 7 // dnc - }, - item_9: ItemSpecials { special1: 8, special2: 8, special3: 8 // dnc - }, - item_10: ItemSpecials { special1: 9, special2: 9, special3: 9 // dnc - }, + item_5: ItemSpecials { special1: 4, special2: 23, special3: 2 }, + item_6: ItemSpecials { special1: 5, special2: 5, special3: 5 }, + item_7: ItemSpecials { special1: 6, special2: 6, special3: 6 }, + item_8: ItemSpecials { special1: 7, special2: 7, special3: 7 }, + item_9: ItemSpecials { special1: 8, special2: 8, special3: 8 }, + item_10: ItemSpecials { special1: 9, special2: 9, special3: 9 }, mutated: false, }; // pack and then unpack the specials - let unpacked: ItemSpecialsStorage = Packing::unpack(storage.pack()); + let unpacked: ItemSpecialsStorage = ItemSpecialsStoragePacking::unpack( + ItemSpecialsStoragePacking::pack(storage) + ); // assert the values were not altered using PartialEq assert(unpacked.item_1 == storage.item_1, 'item 1 packing error'); assert(unpacked.item_2 == storage.item_2, 'item 2 packing error'); assert(unpacked.item_3 == storage.item_3, 'item 3 packing error'); assert(unpacked.item_4 == storage.item_4, 'item 4 packing error'); + assert(unpacked.item_5 == storage.item_5, 'item 5 packing error'); assert(unpacked.item_6 == storage.item_6, 'item 6 packing error'); assert(unpacked.item_7 == storage.item_7, 'item 7 packing error'); assert(unpacked.item_8 == storage.item_8, 'item 8 packing error'); assert(unpacked.item_9 == storage.item_9, 'item 9 packing error'); assert(unpacked.item_10 == storage.item_10, 'item 10 packing error'); - - // item 5 is special in that it attempts to overflow the packing - // assert the packing overflow protection works and instead of - // overflowing, sets these values to max - assert(unpacked.item_5.special1 == MAX_SPECIAL1, 'special1 max u8 check'); - assert(unpacked.item_5.special2 == MAX_SPECIAL2, 'special2 max u8 check'); - assert(unpacked.item_5.special3 == MAX_SPECIAL3, 'special3 max u8 check'); } #[test] diff --git a/contracts/adventurer/src/item_primitive.cairo b/contracts/adventurer/src/item_primitive.cairo index 3770eb351..d36402645 100644 --- a/contracts/adventurer/src/item_primitive.cairo +++ b/contracts/adventurer/src/item_primitive.cairo @@ -1,6 +1,6 @@ +use starknet::{StorePacking}; use option::OptionTrait; use traits::{TryInto, Into}; -use pack::{pack::{Packing, rshift_split}, constants::pow}; use lootitems::loot::{ItemId}; #[derive(Drop, Copy, PartialEq, Serde)] // 21 bits @@ -10,30 +10,29 @@ struct ItemPrimitive { metadata: u8, // 5 bits } -impl ItemPrimitivePacking of Packing { - fn pack(self: ItemPrimitive) -> felt252 { - (self.id.into() + self.xp.into() * pow::TWO_POW_7 + self.metadata.into() * pow::TWO_POW_16) - .try_into() - .expect('pack ItemPrimitive') +const TWO_POW_5: u256 = 0x20; +const TWO_POW_7: u256 = 0x80; +const TWO_POW_9: u256 = 0x200; +const TWO_POW_16: u256 = 0x10000; + +impl ItemPrimitivePacking of StorePacking { + fn pack(value: ItemPrimitive) -> felt252 { + (value.id.into() + value.xp.into() * TWO_POW_7 + value.metadata.into() * TWO_POW_16) + .try_into().unwrap() } - fn unpack(packed: felt252) -> ItemPrimitive { - let packed = packed.into(); - let (packed, id) = rshift_split(packed, pow::TWO_POW_7); - let (packed, xp) = rshift_split(packed, pow::TWO_POW_9); - let (_, metadata) = rshift_split(packed, pow::TWO_POW_5); + fn unpack(value: felt252) -> ItemPrimitive { + let packed = value.into(); + let (packed, id) = integer::U256DivRem::div_rem(packed, TWO_POW_7.try_into().unwrap()); + let (packed, xp) = integer::U256DivRem::div_rem(packed, TWO_POW_9.try_into().unwrap()); + let (_, metadata) = integer::U256DivRem::div_rem(packed, TWO_POW_5.try_into().unwrap()); ItemPrimitive { - id: id.try_into().expect('unpack ItemPrimitive id'), - xp: xp.try_into().expect('unpack ItemPrimitive xp'), - metadata: metadata.try_into().expect('unpack ItemPrimitive metadata') + id: id.try_into().unwrap(), + xp: xp.try_into().unwrap(), + metadata: metadata.try_into().unwrap() } } - - // TODO: add overflow pack protection - fn overflow_pack_protection(self: ItemPrimitive) -> ItemPrimitive { - self - } } #[generate_trait] @@ -138,7 +137,7 @@ mod tests { fn test_item_primitive_packing() { let item = ItemPrimitive { id: 1, xp: 2, metadata: 3 }; - let packed = item.pack(); + let packed = ItemPrimitivePacking::pack(item); let unpacked = ItemPrimitivePacking::unpack(packed); assert(item.id == unpacked.id, 'id should be the same'); @@ -148,7 +147,7 @@ mod tests { // max value case let item = ItemPrimitive { id: 127, xp: 511, metadata: 31 }; - let packed = item.pack(); + let packed = ItemPrimitivePacking::pack(item); let unpacked = ItemPrimitivePacking::unpack(packed); assert(item.id == unpacked.id, 'id should be the same'); assert(item.xp == unpacked.xp, 'xp should be the same'); @@ -156,7 +155,7 @@ mod tests { // overflow case let item = ItemPrimitive { id: 128, xp: 512, metadata: 32 }; - let packed = item.pack(); + let packed = ItemPrimitivePacking::pack(item); let unpacked = ItemPrimitivePacking::unpack(packed); assert(unpacked.id == 0, 'id should overflow to 0'); assert(unpacked.xp == 1, 'xp should overflow to 1'); diff --git a/contracts/game/src/game/game_entropy.cairo b/contracts/game/src/game/game_entropy.cairo index 2404519be..5ff64ec2a 100644 --- a/contracts/game/src/game/game_entropy.cairo +++ b/contracts/game/src/game/game_entropy.cairo @@ -1,4 +1,4 @@ -use pack::{constants::pow, pack::{Packing, rshift_split}}; +use starknet::{StorePacking}; #[derive(Drop, Copy, Serde)] struct GameEntropy { @@ -6,27 +6,23 @@ struct GameEntropy { last_updated: u64, } -impl GameEntropyPacking of Packing { - fn pack(self: GameEntropy) -> felt252 { - (self.entropy.into() - + self.last_updated.into() * pow::TWO_POW_128) - .try_into() - .expect('pack GameEntropy') +const TWO_POW_128: u256 = 0x100000000000000000000000000000000; + +impl GameEntropyPacking of StorePacking { + fn pack(value: GameEntropy) -> felt252 { + (value.entropy.into() + (value.last_updated.into() * TWO_POW_128)).try_into().unwrap() } - fn unpack(packed: felt252) -> GameEntropy { - let packed = packed.into(); - let (packed, entropy) = rshift_split(packed, pow::TWO_POW_128); - let (_, last_updated) = rshift_split(packed, pow::TWO_POW_128); + fn unpack(value: felt252) -> GameEntropy { + let packed = value.into(); + let (packed, entropy) = integer::U256DivRem::div_rem(packed, TWO_POW_128.try_into().unwrap()); + let (_, last_updated) = integer::U256DivRem::div_rem(packed, TWO_POW_128.try_into().unwrap()); GameEntropy { - entropy: entropy.try_into().unwrap(), last_updated: last_updated.try_into().unwrap(), + entropy: entropy.try_into().unwrap(), + last_updated: last_updated.try_into().unwrap(), } } - // Not used for game entropy - fn overflow_pack_protection(self: GameEntropy) -> GameEntropy { - self - } } // --------------------------- @@ -35,19 +31,20 @@ impl GameEntropyPacking of Packing { #[cfg(test)] mod tests { use game::game::game_entropy::{GameEntropy, GameEntropyPacking}; - use pack::{pack::{Packing}}; #[test] #[available_gas(3000000)] fn test_packing_and_unpacking_game_entropy() { + // max value case let game_entropy = GameEntropy { entropy: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, last_updated: 0xFFFFFFFFFFFFFFFF }; - let unpacked: GameEntropy = Packing::unpack(game_entropy.pack()); + let unpacked: GameEntropy = GameEntropyPacking::unpack(GameEntropyPacking::pack(game_entropy)); assert(unpacked.entropy == game_entropy.entropy, 'wrong entropy max value'); assert(unpacked.last_updated == game_entropy.last_updated, 'wrong last_updated max value'); + // zero case let game_entropy = GameEntropy { entropy: 0, last_updated: 0 }; - let unpacked: GameEntropy = Packing::unpack(game_entropy.pack()); + let unpacked: GameEntropy = GameEntropyPacking::unpack(GameEntropyPacking::pack(game_entropy)); assert(unpacked.entropy == game_entropy.entropy, 'wrong entropy zero'); assert(unpacked.last_updated == game_entropy.last_updated, 'wrong last_updated zero'); diff --git a/contracts/game/src/lib.cairo b/contracts/game/src/lib.cairo index bd8e48abf..e0a128951 100644 --- a/contracts/game/src/lib.cairo +++ b/contracts/game/src/lib.cairo @@ -16,16 +16,13 @@ mod Game { const LOOT_NAME_STORAGE_INDEX_1: u256 = 0; const LOOT_NAME_STORAGE_INDEX_2: u256 = 1; - use option::OptionTrait; - use box::BoxTrait; - use core::array::SpanTrait; - use starknet::{ - get_caller_address, ContractAddress, ContractAddressIntoFelt252, contract_address_const + use core::{ + array::{SpanTrait, ArrayTrait}, integer::u256_try_as_non_zero, traits::{TryInto, Into}, + clone::Clone, poseidon::poseidon_hash_span, option::OptionTrait, box::BoxTrait, + starknet::{ + get_caller_address, ContractAddress, ContractAddressIntoFelt252, contract_address_const + }, }; - use core::traits::{TryInto, Into}; - use core::clone::Clone; - use array::ArrayTrait; - use poseidon::poseidon_hash_span; use openzeppelin::token::erc20::interface::{ IERC20Camel, IERC20CamelDispatcher, IERC20CamelDispatcherTrait, IERC20CamelLibraryDispatcher @@ -44,7 +41,6 @@ mod Game { use lootitems::{ loot::{ILoot, Loot, ImplLoot}, constants::{ItemId, NamePrefixLength, NameSuffixLength} }; - use pack::{pack::{Packing, rshift_split}, constants::{MASK_16, pow, MASK_8, MASK_BOOL, mask}}; use survivor::{ adventurer::{Adventurer, ImplAdventurer, IAdventurer}, adventurer_stats::{Stats, StatUtils}, item_primitive::{ImplItemPrimitive, ItemPrimitive}, bag::{Bag, IBag, ImplBag}, @@ -71,13 +67,12 @@ mod Game { #[storage] struct Storage { - _game_entropy: felt252, - _adventurer: LegacyMap::, + _game_entropy: GameEntropy, + _adventurer: LegacyMap::, _owner: LegacyMap::, - _adventurer_meta: LegacyMap::, - _loot: LegacyMap::, - _loot_special_names: LegacyMap::<(u256, u256), felt252>, - _bag: LegacyMap::, + _adventurer_meta: LegacyMap::, + _item_specials: LegacyMap::<(u256, u256), ItemSpecialsStorage>, + _bag: LegacyMap::, _counter: u256, _lords: ContractAddress, _dao: ContractAddress, @@ -805,7 +800,7 @@ mod Game { fn get_special_storage( self: @ContractState, adventurer_id: u256, storage_index: u256 ) -> ItemSpecialsStorage { - Packing::unpack(self._loot_special_names.read((adventurer_id, storage_index))) + self._item_specials.read((adventurer_id, storage_index)) } fn get_beast_type(self: @ContractState, beast_id: u8) -> u8 { ImplCombat::type_to_u8(ImplBeast::get_type(beast_id)) @@ -1987,13 +1982,13 @@ mod Game { // ------------ Helper Functions ------------ // // ------------------------------------------ // fn _unpack_adventurer(self: @ContractState, adventurer_id: u256) -> Adventurer { - Packing::unpack(self._adventurer.read(adventurer_id)) + self._adventurer.read(adventurer_id) } fn _unpack_adventurer_and_bag_with_stat_boosts( self: @ContractState, adventurer_id: u256 ) -> (Adventurer, Stats, Bag) { // unpack adventurer - let mut adventurer: Adventurer = Packing::unpack(self._adventurer.read(adventurer_id)); + let mut adventurer: Adventurer = self._adventurer.read(adventurer_id); // start with no stat boosts let mut stat_boosts = StatUtils::new(); // if adventurer has item specials @@ -2017,7 +2012,7 @@ mod Game { #[inline(always)] fn _pack_adventurer(ref self: ContractState, adventurer_id: u256, adventurer: Adventurer) { - self._adventurer.write(adventurer_id, adventurer.pack()); + self._adventurer.write(adventurer_id, adventurer); } // @dev Packs and saves an adventurer after removing stat boosts. // @param adventurer_id The ID of the adventurer to be modified. @@ -2029,35 +2024,37 @@ mod Game { // remove stat boosts adventurer.remove_stat_boosts(stat_boosts); - // pack and save - self._adventurer.write(adventurer_id, adventurer.pack()); + // save adventurer + self._adventurer.write(adventurer_id, adventurer); } #[inline(always)] fn _unpacked_bag(self: @ContractState, adventurer_id: u256) -> Bag { - Packing::unpack(self._bag.read(adventurer_id)) + self._bag.read(adventurer_id) } #[inline(always)] fn _pack_bag(ref self: ContractState, adventurer_id: u256, bag: Bag) { - self._bag.write(adventurer_id, bag.pack()); + self._bag.write(adventurer_id, bag); } #[inline(always)] fn _unpack_adventurer_meta(self: @ContractState, adventurer_id: u256) -> AdventurerMetadata { - Packing::unpack(self._adventurer_meta.read(adventurer_id)) + self._adventurer_meta.read(adventurer_id) } #[inline(always)] fn _pack_adventurer_meta( ref self: ContractState, adventurer_id: u256, adventurer_meta: AdventurerMetadata ) { - self._adventurer_meta.write(adventurer_id, adventurer_meta.pack()); + self._adventurer_meta.write(adventurer_id, adventurer_meta); } #[inline(always)] fn _unpack_game_entropy(self: @ContractState) -> GameEntropy { - Packing::unpack(self._game_entropy.read()) + //Packing::unpack(self._game_entropy.read()) + self._game_entropy.read() } #[inline(always)] fn _pack_game_entropy(ref self: ContractState, game_entropy: GameEntropy) { - self._game_entropy.write(game_entropy.pack()); + //self._game_entropy.write(game_entropy.pack()); + self._game_entropy.write(game_entropy); } /// @title Internal Rotate Game Entropy Function @@ -2081,7 +2078,9 @@ mod Game { hash_span.append(timestamp.into()); hash_span.append(blocknumber.into()); let poseidon: felt252 = poseidon_hash_span(hash_span.span()).into(); - let (_, entropy) = rshift_split(poseidon.into(), U128_MAX.into()); + let (_, entropy) = integer::U256DivRem::div_rem( + poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); // set new game entropy and block number of update let updated_game_entropy = GameEntropy { @@ -2128,9 +2127,7 @@ mod Game { storage_index: u256, loot_special_names_storage: ItemSpecialsStorage, ) { - self - ._loot_special_names - .write((adventurer_id, storage_index), loot_special_names_storage.pack()); + self._item_specials.write((adventurer_id, storage_index), loot_special_names_storage); } #[inline(always)] @@ -2147,7 +2144,7 @@ mod Game { fn _get_specials_storage( self: @ContractState, adventurer_id: u256, storage_index: u256 ) -> ItemSpecialsStorage { - Packing::unpack(self._loot_special_names.read((adventurer_id, storage_index))) + self._item_specials.read((adventurer_id, storage_index)) } #[inline(always)] diff --git a/contracts/loot/Scarb.toml b/contracts/loot/Scarb.toml index a70e19b4b..e09a9f4cc 100644 --- a/contracts/loot/Scarb.toml +++ b/contracts/loot/Scarb.toml @@ -5,5 +5,4 @@ version = "0.1.0" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -pack = { path = "../pack" } combat = { path = "../combat" } diff --git a/contracts/loot/src/loot.cairo b/contracts/loot/src/loot.cairo index ec62d9ba6..ff5ded1d8 100644 --- a/contracts/loot/src/loot.cairo +++ b/contracts/loot/src/loot.cairo @@ -1,9 +1,9 @@ +use starknet::{StorePacking}; use traits::{TryInto, Into}; use option::OptionTrait; use core::{serde::Serde, clone::Clone}; use combat::{combat::ImplCombat, constants::CombatEnums::{Type, Tier, Slot}}; -use pack::{pack::{Packing, rshift_split}, constants::pow}; use super::{ constants::{ NamePrefixLength, ItemNameSuffix, ItemId, ItemNamePrefix, NameSuffixLength, @@ -944,46 +944,41 @@ impl ImplLoot of ILoot { } } } - -impl PackingLoot of Packing { - // pack an item for storage - // @param item The item to pack. - // @return The packed item in a felt252 - fn pack(self: Loot) -> felt252 { - let item_tier = ImplCombat::tier_to_u8(self.tier); - let item_type = ImplCombat::type_to_u8(self.item_type); - let item_slot = ImplCombat::slot_to_u8(self.slot); - - (self.id.into() - + item_tier.into() * pow::TWO_POW_8 - + item_type.into() * pow::TWO_POW_16 - + item_slot.into() * pow::TWO_POW_24) +const TWO_POW_8: u256 = 0x100; +const TWO_POW_16: u256 = 0x10000; +const TWO_POW_24: u256 = 0x1000000; + +impl LootPacking of StorePacking { + fn pack(value: Loot) -> felt252 { + let item_tier = ImplCombat::tier_to_u8(value.tier); + let item_type = ImplCombat::type_to_u8(value.item_type); + let item_slot = ImplCombat::slot_to_u8(value.slot); + + (value.id.into() + + item_tier.into() * TWO_POW_8 + + item_type.into() * TWO_POW_16 + + item_slot.into() * TWO_POW_24) .try_into() - .expect('pack Loot') + .unwrap() } - - // unpack an item from storage - // @param packed The item packed as a felt252 - // @return The unpacked item - fn unpack(packed: felt252) -> Loot { - let packed = packed.into(); - let (packed, item_id) = rshift_split(packed, pow::TWO_POW_8); - let (packed, item_tier) = rshift_split(packed, pow::TWO_POW_8); - let (packed, item_type) = rshift_split(packed, pow::TWO_POW_8); - let (_, item_slot) = rshift_split(packed, pow::TWO_POW_8); + fn unpack(value: felt252) -> Loot { + let packed = value.into(); + let (packed, item_id) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); + let (packed, item_tier) = integer::U256DivRem::div_rem( + packed, TWO_POW_8.try_into().unwrap() + ); + let (packed, item_type) = integer::U256DivRem::div_rem( + packed, TWO_POW_8.try_into().unwrap() + ); + let (_, item_slot) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); Loot { - id: item_id.try_into().expect('unpack Loot id'), - tier: ImplCombat::u8_to_tier(item_tier.try_into().expect('unpack Loot tier')), - item_type: ImplCombat::u8_to_type(item_type.try_into().expect('unpack Loot item type')), - slot: ImplCombat::u8_to_slot(item_slot.try_into().expect('unpack Loot slot')) + id: item_id.try_into().unwrap(), + tier: ImplCombat::u8_to_tier(item_tier.try_into().unwrap()), + item_type: ImplCombat::u8_to_type(item_type.try_into().unwrap()), + slot: ImplCombat::u8_to_slot(item_slot.try_into().unwrap()) } } - - // TODO: add overflow pack protection - fn overflow_pack_protection(self: Loot) -> Loot { - self - } } // --------------------------- @@ -996,9 +991,8 @@ mod tests { use core::{serde::Serde, clone::Clone}; use combat::{combat::ImplCombat, constants::CombatEnums::{Type, Tier, Slot}}; - use pack::{pack::{Packing, rshift_split}, constants::pow}; use lootitems::{ - loot::{ImplLoot, ILoot, PackingLoot, Loot}, + loot::{ImplLoot, ILoot, LootPacking, Loot}, constants::{ NamePrefixLength, ItemNameSuffix, ItemId, ItemNamePrefix, NameSuffixLength, ItemSuffixLength, ItemSuffix, NUM_ITEMS, @@ -1271,7 +1265,7 @@ mod tests { id: 1, tier: Tier::T1(()), item_type: Type::Bludgeon_or_Metal(()), slot: Slot::Waist(()) }; - let unpacked: Loot = Packing::unpack(loot.pack()); + let unpacked: Loot = LootPacking::unpack(LootPacking::pack(loot)); assert(loot.id == unpacked.id, 'id'); assert(loot.tier == unpacked.tier, 'tier'); assert(loot.item_type == unpacked.item_type, 'item_type'); diff --git a/contracts/market/src/market.cairo b/contracts/market/src/market.cairo index b8769fa8c..e668ad535 100644 --- a/contracts/market/src/market.cairo +++ b/contracts/market/src/market.cairo @@ -4,13 +4,12 @@ use array::{ArrayTrait, SpanTrait}; use option::OptionTrait; use core::clone::Clone; use poseidon::poseidon_hash_span; +use integer::u256_try_as_non_zero; use lootitems::{loot::{Loot, ILoot, ImplLoot}, constants::{ItemId, NUM_ITEMS}}; use combat::constants::CombatEnums::{Tier, Slot}; use super::constants::{NUM_LOOT_ITEMS, NUMBER_OF_ITEMS_PER_LEVEL, TIER_PRICE}; -use pack::pack::{rshift_split}; - #[derive(Drop, Serde)] struct LootWithPrice { @@ -147,7 +146,9 @@ impl ImplMarket of IMarket { // @param seed a 256-bit unsigned integer representing a unique identifier for the seed. // @return a u8 representing the item ID. fn get_id(seed: u256) -> u8 { - let (_, item_id) = rshift_split(seed, NUM_ITEMS.into()); + let (_, item_id) = integer::U256DivRem::div_rem( + seed, u256_try_as_non_zero(NUM_ITEMS.into()).unwrap() + ); 1 + item_id.try_into().unwrap() } @@ -220,7 +221,9 @@ impl ImplMarket of IMarket { // market seed and the second element is an 8-bit unsigned integer that represents the market offset. fn split_hash_into_seed_and_offset(poseidon_hash: felt252) -> (u256, u8) { // split hash into two u128s, one for market seed, one for offset - let (market_seed, offset) = rshift_split(poseidon_hash.into(), NUM_ITEMS.into() - 1); + let (market_seed, offset) = integer::U256DivRem::div_rem( + poseidon_hash.into(), u256_try_as_non_zero(NUM_ITEMS.into() - 1).unwrap() + ); // return market seed and market offset (market_seed, 1 + offset.try_into().unwrap()) @@ -241,8 +244,6 @@ mod tests { use market::{ market::ImplMarket, constants::{NUM_LOOT_ITEMS, NUMBER_OF_ITEMS_PER_LEVEL, TIER_PRICE} }; - use pack::pack::{rshift_split}; - const TEST_MARKET_SEED: u256 = 515; const TEST_OFFSET: u8 = 3; diff --git a/contracts/pack/.gitignore b/contracts/pack/.gitignore deleted file mode 100644 index eb5a316cb..000000000 --- a/contracts/pack/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/contracts/pack/Scarb.toml b/contracts/pack/Scarb.toml deleted file mode 100644 index 1f6afa068..000000000 --- a/contracts/pack/Scarb.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "pack" -version = "0.1.0" - -# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest - -[dependencies] -# foo = { path = "vendor/foo" } diff --git a/contracts/pack/src/constants.cairo b/contracts/pack/src/constants.cairo deleted file mode 100644 index 5e09a4aa7..000000000 --- a/contracts/pack/src/constants.cairo +++ /dev/null @@ -1,435 +0,0 @@ -mod mask { - const MASK_1: u256 = 0x1; - const MASK_2: u256 = 0x3; - const MASK_3: u256 = 0x7; - const MASK_4: u256 = 0xF; - const MASK_5: u256 = 0x1F; - const MASK_6: u256 = 0x3F; - const MASK_7: u256 = 0x7F; - const MASK_8: u256 = 0xFF; - const MASK_9: u256 = 0x1FF; - const MASK_10: u256 = 0x3FF; - const MASK_11: u256 = 0x7FF; - const MASK_12: u256 = 0xFFF; - const MASK_13: u256 = 0x1FFF; - const MASK_14: u256 = 0x3FFF; - const MASK_15: u256 = 0x7FFF; - const MASK_16: u256 = 0xFFFF; - const MASK_17: u256 = 0x1FFFF; - const MASK_18: u256 = 0x3FFFF; - const MASK_19: u256 = 0x7FFFF; - const MASK_20: u256 = 0xFFFFF; - const MASK_21: u256 = 0x1FFFFF; - const MASK_22: u256 = 0x3FFFFF; - const MASK_23: u256 = 0x7FFFFF; - const MASK_24: u256 = 0xFFFFFF; - const MASK_25: u256 = 0x1FFFFFF; - const MASK_26: u256 = 0x3FFFFFF; - const MASK_27: u256 = 0x7FFFFFF; - const MASK_28: u256 = 0xFFFFFFF; - const MASK_29: u256 = 0x1FFFFFFF; - const MASK_30: u256 = 0x3FFFFFFF; - const MASK_31: u256 = 0x7FFFFFFF; - const MASK_32: u256 = 0xFFFFFFFF; - const MASK_33: u256 = 0x1FFFFFFFF; - const MASK_34: u256 = 0x3FFFFFFFF; - const MASK_35: u256 = 0x7FFFFFFFF; - const MASK_36: u256 = 0xFFFFFFFFF; - const MASK_37: u256 = 0x1FFFFFFFFF; - const MASK_38: u256 = 0x3FFFFFFFFF; - const MASK_39: u256 = 0x7FFFFFFFFF; - const MASK_40: u256 = 0xFFFFFFFFFF; - const MASK_41: u256 = 0x1FFFFFFFFFF; - const MASK_42: u256 = 0x3FFFFFFFFFF; - const MASK_43: u256 = 0x7FFFFFFFFFF; - const MASK_44: u256 = 0xFFFFFFFFFFF; - const MASK_45: u256 = 0x1FFFFFFFFFFF; - const MASK_46: u256 = 0x3FFFFFFFFFFF; - const MASK_47: u256 = 0x7FFFFFFFFFFF; - const MASK_48: u256 = 0xFFFFFFFFFFFF; - const MASK_49: u256 = 0x1FFFFFFFFFFFF; - const MASK_50: u256 = 0x3FFFFFFFFFFFF; - const MASK_51: u256 = 0x7FFFFFFFFFFFF; - const MASK_52: u256 = 0xFFFFFFFFFFFFF; - const MASK_53: u256 = 0x1FFFFFFFFFFFFF; - const MASK_54: u256 = 0x3FFFFFFFFFFFFF; - const MASK_55: u256 = 0x7FFFFFFFFFFFFF; - const MASK_56: u256 = 0xFFFFFFFFFFFFFF; - const MASK_57: u256 = 0x1FFFFFFFFFFFFFF; - const MASK_58: u256 = 0x3FFFFFFFFFFFFFF; - const MASK_59: u256 = 0x7FFFFFFFFFFFFFF; - const MASK_60: u256 = 0xFFFFFFFFFFFFFFF; - const MASK_61: u256 = 0x1FFFFFFFFFFFFFFF; - const MASK_62: u256 = 0x3FFFFFFFFFFFFFFF; - const MASK_63: u256 = 0x7FFFFFFFFFFFFFFF; - const MASK_64: u256 = 0xFFFFFFFFFFFFFFFF; - const MASK_65: u256 = 0x1FFFFFFFFFFFFFFFF; - const MASK_66: u256 = 0x3FFFFFFFFFFFFFFFF; - const MASK_67: u256 = 0x7FFFFFFFFFFFFFFFF; - const MASK_68: u256 = 0xFFFFFFFFFFFFFFFFF; - const MASK_69: u256 = 0x1FFFFFFFFFFFFFFFFF; - const MASK_70: u256 = 0x3FFFFFFFFFFFFFFFFF; - const MASK_71: u256 = 0x7FFFFFFFFFFFFFFFFF; - const MASK_72: u256 = 0xFFFFFFFFFFFFFFFFFF; - const MASK_73: u256 = 0x1FFFFFFFFFFFFFFFFFF; - const MASK_74: u256 = 0x3FFFFFFFFFFFFFFFFFF; - const MASK_75: u256 = 0x7FFFFFFFFFFFFFFFFFF; - const MASK_76: u256 = 0xFFFFFFFFFFFFFFFFFFFF; - const MASK_77: u256 = 0x1FFFFFFFFFFFFFFFFFFFF; - const MASK_78: u256 = 0x3FFFFFFFFFFFFFFFFFFFF; - const MASK_79: u256 = 0x7FFFFFFFFFFFFFFFFFFFF; - const MASK_80: u256 = 0xFFFFFFFFFFFFFFFFFFFFFF; - const MASK_81: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFF; - const MASK_82: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFF; - const MASK_83: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFF; - const MASK_84: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_85: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFF; - const MASK_86: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFF; - const MASK_87: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFF; - const MASK_88: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_89: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_90: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_91: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_92: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_93: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_94: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_95: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_96: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_97: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_98: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_99: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_100: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_101: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_102: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_103: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_104: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_105: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_106: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_107: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_108: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_109: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_110: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_111: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_112: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_113: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_114: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_115: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_116: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_117: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_118: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_119: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_120: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_121: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_122: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_123: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_124: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_125: u256 = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_126: u256 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_127: u256 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; - const MASK_128: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; -} - -const MASK_63: u256 = 0x7FFFFFFFFFFFFFFF; -const MASK_3: u256 = 0b111; -const MASK_6: u256 = 0x3F; -const MASK_8: u256 = 0xFF; // Mask for 8-bit values: id, prefix1, prefix2, suffix -const U128_MASK_8: u128 = 0xFF; - -const MASK_16: u256 = 0xFFFF; // Mask for 16-bit values: xp -const MASK_BOOL: u256 = 0x1; // Mask for boolean values: isEquipped - -mod u128_pow { - const _8: u128 = 0x100; - const _16: u128 = 0x10000; - const _24: u128 = 0x1000000; - const _32: u128 = 0x100000000; - const _40: u128 = 0x10000000000; - const _48: u128 = 0x1000000000000; - const _56: u128 = 0x100000000000000; - const _64: u128 = 0x10000000000000000; - const _72: u128 = 0x1000000000000000000; - const _80: u128 = 0x100000000000000000000; - const _88: u128 = 0x10000000000000000000000; - const _96: u128 = 0x1000000000000000000000000; - const _104: u128 = 0x100000000000000000000000000; - const _112: u128 = 0x10000000000000000000000000000; - const _120: u128 = 0x1000000000000000000000000000000; -} - -mod pow { - const TWO_POW_1: u256 = 0x2; // 2^1 - const TWO_POW_2: u256 = 0x4; // 2^2 - const TWO_POW_3: u256 = 0x8; // 2^3 - const TWO_POW_4: u256 = 0x10; // 2^4 - const TWO_POW_5: u256 = 0x20; // 2^5 - const TWO_POW_6: u256 = 0x40; // 2^6 - const TWO_POW_7: u256 = 0x80; // 2^7 - const TWO_POW_8: u256 = 0x100; // 2^8 - const TWO_POW_9: u256 = 0x200; // 2^9 - const TWO_POW_10: u256 = 0x400; // 2^10 - const TWO_POW_11: u256 = 0x800; // 2^11 - const TWO_POW_12: u256 = 0x1000; // 2^12 - const TWO_POW_13: u256 = 0x2000; // 2^13 - const TWO_POW_14: u256 = 0x4000; // 2^14 - const TWO_POW_15: u256 = 0x8000; // 2^15 - const TWO_POW_16: u256 = 0x10000; // 2^16 - const TWO_POW_17: u256 = 0x20000; // 2^17 - const TWO_POW_18: u256 = 0x40000; // 2^18 - const TWO_POW_19: u256 = 0x80000; // 2^19 - const TWO_POW_20: u256 = 0x100000; // 2^20 - const TWO_POW_21: u256 = 0x200000; // 2^21 - const TWO_POW_22: u256 = 0x400000; // 2^22 - const TWO_POW_23: u256 = 0x800000; // 2^23 - const TWO_POW_24: u256 = 0x1000000; // 2^24 - const TWO_POW_25: u256 = 0x2000000; // 2^25 - const TWO_POW_26: u256 = 0x4000000; // 2^26 - const TWO_POW_27: u256 = 0x8000000; // 2^27 - const TWO_POW_28: u256 = 0x10000000; // 2^28 - const TWO_POW_29: u256 = 0x20000000; // 2^29 - const TWO_POW_30: u256 = 0x40000000; // 2^30 - const TWO_POW_31: u256 = 0x80000000; // 2^31 - const TWO_POW_32: u256 = 0x100000000; // 2^32 - const TWO_POW_33: u256 = 0x200000000; // 2^33 - const TWO_POW_34: u256 = 0x400000000; // 2^34 - const TWO_POW_35: u256 = 0x800000000; // 2^35 - const TWO_POW_36: u256 = 0x1000000000; // 2^36 - const TWO_POW_37: u256 = 0x2000000000; // 2^37 - const TWO_POW_38: u256 = 0x4000000000; // 2^38 - const TWO_POW_39: u256 = 0x8000000000; // 2^39 - const TWO_POW_40: u256 = 0x10000000000; // 2^40 - const TWO_POW_41: u256 = 0x20000000000; // 2^41 - const TWO_POW_42: u256 = 0x40000000000; // 2^42 - const TWO_POW_43: u256 = 0x80000000000; // 2^43 - const TWO_POW_44: u256 = 0x100000000000; // 2^44 - const TWO_POW_45: u256 = 0x200000000000; // 2^45 - const TWO_POW_46: u256 = 0x400000000000; // 2^46 - const TWO_POW_47: u256 = 0x800000000000; // 2^47 - const TWO_POW_48: u256 = 0x1000000000000; // 2^48 - const TWO_POW_49: u256 = 0x2000000000000; // 2^49 - const TWO_POW_50: u256 = 0x4000000000000; // 2^50 - const TWO_POW_51: u256 = 0x8000000000000; // 2^51 - const TWO_POW_52: u256 = 0x10000000000000; // 2^52 - const TWO_POW_53: u256 = 0x20000000000000; // 2^53 - const TWO_POW_54: u256 = 0x40000000000000; // 2^54 - const TWO_POW_55: u256 = 0x80000000000000; // 2^55 - const TWO_POW_56: u256 = 0x100000000000000; // 2^56 - const TWO_POW_57: u256 = 0x200000000000000; // 2^57 - const TWO_POW_58: u256 = 0x400000000000000; // 2^58 - const TWO_POW_59: u256 = 0x800000000000000; // 2^59 - const TWO_POW_60: u256 = 0x1000000000000000; // 2^60 - const TWO_POW_61: u256 = 0x2000000000000000; // 2^61 - const TWO_POW_62: u256 = 0x4000000000000000; // 2^62 - const TWO_POW_63: u256 = 0x8000000000000000; // 2^63 - const TWO_POW_64: u256 = 0x10000000000000000; // 2^64 - const TWO_POW_65: u256 = 0x20000000000000000; // 2^65 - const TWO_POW_66: u256 = 0x40000000000000000; // 2^66 - const TWO_POW_67: u256 = 0x80000000000000000; // 2^67 - const TWO_POW_68: u256 = 0x100000000000000000; // 2^68 - const TWO_POW_69: u256 = 0x200000000000000000; // 2^69 - const TWO_POW_70: u256 = 0x400000000000000000; // 2^70 - const TWO_POW_71: u256 = 0x800000000000000000; // 2^71 - const TWO_POW_72: u256 = 0x1000000000000000000; // 2^72 - const TWO_POW_73: u256 = 0x2000000000000000000; // 2^73 - const TWO_POW_74: u256 = 0x4000000000000000000; // 2^74 - const TWO_POW_75: u256 = 0x8000000000000000000; // 2^75 - const TWO_POW_76: u256 = 0x10000000000000000000; // 2^76 - const TWO_POW_77: u256 = 0x20000000000000000000; // 2^77 - const TWO_POW_78: u256 = 0x40000000000000000000; // 2^78 - const TWO_POW_79: u256 = 0x80000000000000000000; // 2^79 - const TWO_POW_80: u256 = 0x100000000000000000000; // 2^80 - const TWO_POW_81: u256 = 0x200000000000000000000; // 2^81 - const TWO_POW_82: u256 = 0x400000000000000000000; // 2^82 - const TWO_POW_83: u256 = 0x800000000000000000000; // 2^83 - const TWO_POW_84: u256 = 0x1000000000000000000000; // 2^84 - const TWO_POW_85: u256 = 0x2000000000000000000000; // 2^85 - const TWO_POW_86: u256 = 0x4000000000000000000000; // 2^86 - const TWO_POW_87: u256 = 0x8000000000000000000000; // 2^87 - const TWO_POW_88: u256 = 0x10000000000000000000000; // 2^88 - const TWO_POW_89: u256 = 0x20000000000000000000000; // 2^89 - const TWO_POW_90: u256 = 0x40000000000000000000000; // 2^90 - const TWO_POW_91: u256 = 0x80000000000000000000000; // 2^91 - const TWO_POW_92: u256 = 0x100000000000000000000000; // 2^92 - const TWO_POW_93: u256 = 0x200000000000000000000000; // 2^93 - const TWO_POW_94: u256 = 0x400000000000000000000000; // 2^94 - const TWO_POW_95: u256 = 0x800000000000000000000000; // 2^95 - const TWO_POW_96: u256 = 0x1000000000000000000000000; // 2^96 - const TWO_POW_97: u256 = 0x2000000000000000000000000; // 2^97 - const TWO_POW_98: u256 = 0x4000000000000000000000000; // 2^98 - const TWO_POW_99: u256 = 0x8000000000000000000000000; // 2^99 - const TWO_POW_100: u256 = 0x10000000000000000000000000; // 2^100 - const TWO_POW_101: u256 = 0x20000000000000000000000000; // 2^101 - const TWO_POW_102: u256 = 0x40000000000000000000000000; // 2^102 - const TWO_POW_103: u256 = 0x80000000000000000000000000; // 2^103 - const TWO_POW_104: u256 = 0x100000000000000000000000000; // 2^104 - const TWO_POW_105: u256 = 0x200000000000000000000000000; // 2^105 - const TWO_POW_106: u256 = 0x400000000000000000000000000; // 2^106 - const TWO_POW_107: u256 = 0x800000000000000000000000000; // 2^107 - const TWO_POW_108: u256 = 0x1000000000000000000000000000; // 2^108 - const TWO_POW_109: u256 = 0x2000000000000000000000000000; // 2^109 - const TWO_POW_110: u256 = 0x4000000000000000000000000000; // 2^110 - const TWO_POW_111: u256 = 0x8000000000000000000000000000; // 2^111 - const TWO_POW_112: u256 = 0x10000000000000000000000000000; // 2^112 - const TWO_POW_113: u256 = 0x20000000000000000000000000000; // 2^113 - const TWO_POW_114: u256 = 0x40000000000000000000000000000; // 2^114 - const TWO_POW_115: u256 = 0x80000000000000000000000000000; // 2^115 - const TWO_POW_116: u256 = 0x100000000000000000000000000000; // 2^116 - const TWO_POW_117: u256 = 0x200000000000000000000000000000; // 2^117 - const TWO_POW_118: u256 = 0x400000000000000000000000000000; // 2^118 - const TWO_POW_119: u256 = 0x800000000000000000000000000000; // 2^119 - const TWO_POW_120: u256 = 0x1000000000000000000000000000000; // 2^120 - const TWO_POW_121: u256 = 0x2000000000000000000000000000000; // 2^121 - const TWO_POW_122: u256 = 0x4000000000000000000000000000000; // 2^122 - const TWO_POW_123: u256 = 0x8000000000000000000000000000000; // 2^123 - const TWO_POW_124: u256 = 0x10000000000000000000000000000000; // 2^124 - const TWO_POW_125: u256 = 0x20000000000000000000000000000000; // 2^125 - const TWO_POW_126: u256 = 0x40000000000000000000000000000000; // 2^126 - const TWO_POW_127: u256 = 0x80000000000000000000000000000000; // 2^127 - const TWO_POW_128: u256 = 0x100000000000000000000000000000000; // 2^128 - const TWO_POW_129: u256 = 0x200000000000000000000000000000000; // 2^129 - const TWO_POW_130: u256 = 0x400000000000000000000000000000000; // 2^130 - const TWO_POW_131: u256 = 0x800000000000000000000000000000000; // 2^131 - const TWO_POW_132: u256 = 0x1000000000000000000000000000000000; // 2^132 - const TWO_POW_133: u256 = 0x2000000000000000000000000000000000; // 2^133 - const TWO_POW_134: u256 = 0x4000000000000000000000000000000000; // 2^134 - const TWO_POW_135: u256 = 0x8000000000000000000000000000000000; // 2^135 - const TWO_POW_136: u256 = 0x10000000000000000000000000000000000; // 2^136 - const TWO_POW_137: u256 = 0x20000000000000000000000000000000000; // 2^137 - const TWO_POW_138: u256 = 0x40000000000000000000000000000000000; // 2^138 - const TWO_POW_139: u256 = 0x80000000000000000000000000000000000; // 2^139 - const TWO_POW_140: u256 = 0x100000000000000000000000000000000000; // 2^140 - const TWO_POW_141: u256 = 0x200000000000000000000000000000000000; // 2^141 - const TWO_POW_142: u256 = 0x400000000000000000000000000000000000; // 2^142 - const TWO_POW_143: u256 = 0x800000000000000000000000000000000000; // 2^143 - const TWO_POW_144: u256 = 0x1000000000000000000000000000000000000; // 2^144 - const TWO_POW_145: u256 = 0x2000000000000000000000000000000000000; // 2^145 - const TWO_POW_146: u256 = 0x4000000000000000000000000000000000000; // 2^146 - const TWO_POW_147: u256 = 0x8000000000000000000000000000000000000; // 2^147 - const TWO_POW_148: u256 = 0x10000000000000000000000000000000000000; // 2^148 - const TWO_POW_149: u256 = 0x20000000000000000000000000000000000000; // 2^149 - const TWO_POW_150: u256 = 0x40000000000000000000000000000000000000; // 2^150 - const TWO_POW_151: u256 = 0x80000000000000000000000000000000000000; // 2^151 - const TWO_POW_152: u256 = 0x100000000000000000000000000000000000000; // 2^152 - const TWO_POW_153: u256 = 0x200000000000000000000000000000000000000; // 2^153 - const TWO_POW_154: u256 = 0x400000000000000000000000000000000000000; // 2^154 - const TWO_POW_155: u256 = 0x800000000000000000000000000000000000000; // 2^155 - const TWO_POW_156: u256 = 0x1000000000000000000000000000000000000000; // 2^156 - const TWO_POW_157: u256 = 0x2000000000000000000000000000000000000000; // 2^157 - const TWO_POW_158: u256 = 0x4000000000000000000000000000000000000000; // 2^158 - const TWO_POW_159: u256 = 0x8000000000000000000000000000000000000000; // 2^159 - const TWO_POW_160: u256 = 0x10000000000000000000000000000000000000000; // 2^160 - const TWO_POW_161: u256 = 0x20000000000000000000000000000000000000000; // 2^161 - const TWO_POW_162: u256 = 0x40000000000000000000000000000000000000000; // 2^162 - const TWO_POW_163: u256 = 0x80000000000000000000000000000000000000000; // 2^163 - const TWO_POW_164: u256 = 0x100000000000000000000000000000000000000000; // 2^164 - const TWO_POW_165: u256 = 0x200000000000000000000000000000000000000000; // 2^165 - const TWO_POW_166: u256 = 0x400000000000000000000000000000000000000000; // 2^166 - const TWO_POW_167: u256 = 0x800000000000000000000000000000000000000000; // 2^167 - const TWO_POW_168: u256 = 0x1000000000000000000000000000000000000000000; // 2^168 - const TWO_POW_169: u256 = 0x2000000000000000000000000000000000000000000; // 2^169 - const TWO_POW_170: u256 = 0x4000000000000000000000000000000000000000000; // 2^170 - const TWO_POW_171: u256 = 0x8000000000000000000000000000000000000000000; // 2^171 - const TWO_POW_172: u256 = 0x10000000000000000000000000000000000000000000; // 2^172 - const TWO_POW_173: u256 = 0x20000000000000000000000000000000000000000000; // 2^173 - const TWO_POW_174: u256 = 0x40000000000000000000000000000000000000000000; // 2^174 - const TWO_POW_175: u256 = 0x80000000000000000000000000000000000000000000; // 2^175 - const TWO_POW_176: u256 = 0x100000000000000000000000000000000000000000000; // 2^176 - const TWO_POW_177: u256 = 0x200000000000000000000000000000000000000000000; // 2^177 - const TWO_POW_178: u256 = 0x400000000000000000000000000000000000000000000; // 2^178 - const TWO_POW_179: u256 = 0x800000000000000000000000000000000000000000000; // 2^179 - const TWO_POW_180: u256 = 0x1000000000000000000000000000000000000000000000; // 2^180 - const TWO_POW_181: u256 = 0x2000000000000000000000000000000000000000000000; // 2^181 - const TWO_POW_182: u256 = 0x4000000000000000000000000000000000000000000000; // 2^182 - const TWO_POW_183: u256 = 0x8000000000000000000000000000000000000000000000; // 2^183 - const TWO_POW_184: u256 = 0x10000000000000000000000000000000000000000000000; // 2^184 - const TWO_POW_185: u256 = 0x20000000000000000000000000000000000000000000000; // 2^185 - const TWO_POW_186: u256 = 0x40000000000000000000000000000000000000000000000; // 2^186 - const TWO_POW_187: u256 = 0x80000000000000000000000000000000000000000000000; // 2^187 - const TWO_POW_188: u256 = 0x100000000000000000000000000000000000000000000000; // 2^188 - const TWO_POW_189: u256 = 0x200000000000000000000000000000000000000000000000; // 2^189 - const TWO_POW_190: u256 = 0x400000000000000000000000000000000000000000000000; // 2^190 - const TWO_POW_191: u256 = 0x800000000000000000000000000000000000000000000000; // 2^191 - const TWO_POW_192: u256 = 0x1000000000000000000000000000000000000000000000000; // 2^192 - const TWO_POW_193: u256 = 0x2000000000000000000000000000000000000000000000000; // 2^193 - const TWO_POW_194: u256 = 0x4000000000000000000000000000000000000000000000000; // 2^194 - const TWO_POW_195: u256 = 0x8000000000000000000000000000000000000000000000000; // 2^195 - const TWO_POW_196: u256 = 0x10000000000000000000000000000000000000000000000000; // 2^196 - const TWO_POW_197: u256 = 0x20000000000000000000000000000000000000000000000000; // 2^197 - const TWO_POW_198: u256 = 0x40000000000000000000000000000000000000000000000000; // 2^198 - const TWO_POW_199: u256 = 0x80000000000000000000000000000000000000000000000000; // 2^199 - const TWO_POW_200: u256 = 0x100000000000000000000000000000000000000000000000000; // 2^200 - const TWO_POW_201: u256 = 0x200000000000000000000000000000000000000000000000000; // 2^201 - const TWO_POW_202: u256 = 0x400000000000000000000000000000000000000000000000000; // 2^202 - const TWO_POW_203: u256 = 0x800000000000000000000000000000000000000000000000000; // 2^203 - const TWO_POW_204: u256 = 0x1000000000000000000000000000000000000000000000000000; // 2^204 - const TWO_POW_205: u256 = 0x2000000000000000000000000000000000000000000000000000; // 2^205 - const TWO_POW_206: u256 = 0x4000000000000000000000000000000000000000000000000000; // 2^206 - const TWO_POW_207: u256 = 0x8000000000000000000000000000000000000000000000000000; // 2^207 - const TWO_POW_208: u256 = 0x10000000000000000000000000000000000000000000000000000; // 2^208 - const TWO_POW_209: u256 = 0x20000000000000000000000000000000000000000000000000000; // 2^209 - const TWO_POW_210: u256 = 0x40000000000000000000000000000000000000000000000000000; // 2^210 - const TWO_POW_211: u256 = 0x80000000000000000000000000000000000000000000000000000; // 2^211 - const TWO_POW_212: u256 = 0x100000000000000000000000000000000000000000000000000000; // 2^212 - const TWO_POW_213: u256 = 0x200000000000000000000000000000000000000000000000000000; // 2^213 - const TWO_POW_214: u256 = 0x400000000000000000000000000000000000000000000000000000; // 2^214 - const TWO_POW_215: u256 = 0x800000000000000000000000000000000000000000000000000000; // 2^215 - const TWO_POW_216: u256 = 0x1000000000000000000000000000000000000000000000000000000; // 2^216 - const TWO_POW_217: u256 = 0x2000000000000000000000000000000000000000000000000000000; // 2^217 - const TWO_POW_218: u256 = 0x4000000000000000000000000000000000000000000000000000000; // 2^218 - const TWO_POW_219: u256 = 0x8000000000000000000000000000000000000000000000000000000; // 2^219 - const TWO_POW_220: u256 = 0x10000000000000000000000000000000000000000000000000000000; // 2^220 - const TWO_POW_221: u256 = 0x20000000000000000000000000000000000000000000000000000000; // 2^221 - const TWO_POW_222: u256 = 0x40000000000000000000000000000000000000000000000000000000; // 2^222 - const TWO_POW_223: u256 = 0x80000000000000000000000000000000000000000000000000000000; // 2^223 - const TWO_POW_224: u256 = 0x100000000000000000000000000000000000000000000000000000000; // 2^224 - const TWO_POW_225: u256 = 0x200000000000000000000000000000000000000000000000000000000; // 2^225 - const TWO_POW_226: u256 = 0x400000000000000000000000000000000000000000000000000000000; // 2^226 - const TWO_POW_227: u256 = 0x800000000000000000000000000000000000000000000000000000000; // 2^227 - const TWO_POW_228: u256 = 0x1000000000000000000000000000000000000000000000000000000000; // 2^228 - const TWO_POW_229: u256 = 0x2000000000000000000000000000000000000000000000000000000000; // 2^229 - const TWO_POW_230: u256 = 0x4000000000000000000000000000000000000000000000000000000000; // 2^230 - const TWO_POW_231: u256 = 0x8000000000000000000000000000000000000000000000000000000000; // 2^231 - const TWO_POW_232: u256 = - 0x10000000000000000000000000000000000000000000000000000000000; // 2^232 - const TWO_POW_233: u256 = - 0x20000000000000000000000000000000000000000000000000000000000; // 2^233 - const TWO_POW_234: u256 = - 0x40000000000000000000000000000000000000000000000000000000000; // 2^234 - const TWO_POW_235: u256 = - 0x80000000000000000000000000000000000000000000000000000000000; // 2^235 - const TWO_POW_236: u256 = - 0x100000000000000000000000000000000000000000000000000000000000; // 2^236 - const TWO_POW_237: u256 = - 0x200000000000000000000000000000000000000000000000000000000000; // 2^237 - const TWO_POW_238: u256 = - 0x400000000000000000000000000000000000000000000000000000000000; // 2^238 - const TWO_POW_239: u256 = - 0x800000000000000000000000000000000000000000000000000000000000; // 2^239 - const TWO_POW_240: u256 = - 0x1000000000000000000000000000000000000000000000000000000000000; // 2^240 - const TWO_POW_241: u256 = - 0x2000000000000000000000000000000000000000000000000000000000000; // 2^241 - const TWO_POW_242: u256 = - 0x4000000000000000000000000000000000000000000000000000000000000; // 2^242 - const TWO_POW_243: u256 = - 0x8000000000000000000000000000000000000000000000000000000000000; // 2^243 - const TWO_POW_244: u256 = - 0x10000000000000000000000000000000000000000000000000000000000000; // 2^244 - const TWO_POW_245: u256 = - 0x20000000000000000000000000000000000000000000000000000000000000; // 2^245 - const TWO_POW_246: u256 = - 0x40000000000000000000000000000000000000000000000000000000000000; // 2^246 - const TWO_POW_247: u256 = - 0x80000000000000000000000000000000000000000000000000000000000000; // 2^247 - const TWO_POW_248: u256 = - 0x100000000000000000000000000000000000000000000000000000000000000; // 2^248 - const TWO_POW_249: u256 = - 0x200000000000000000000000000000000000000000000000000000000000000; // 2^249 - const TWO_POW_250: u256 = - 0x400000000000000000000000000000000000000000000000000000000000000; // 2^250 - const TWO_POW_251: u256 = - 0x800000000000000000000000000000000000000000000000000000000000000; // 2^251 - const TWO_POW_252: u256 = - 0x1000000000000000000000000000000000000000000000000000000000000000; // 2^252 - const TWO_POW_256: u256 = - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // 2^256 -} diff --git a/contracts/pack/src/lib.cairo b/contracts/pack/src/lib.cairo deleted file mode 100644 index 5c25f5326..000000000 --- a/contracts/pack/src/lib.cairo +++ /dev/null @@ -1,2 +0,0 @@ -mod pack; -mod constants; diff --git a/contracts/pack/src/pack.cairo b/contracts/pack/src/pack.cairo deleted file mode 100644 index 48fc92002..000000000 --- a/contracts/pack/src/pack.cairo +++ /dev/null @@ -1,52 +0,0 @@ -use option::OptionTrait; -use traits::{Into, TryInto}; - -trait Packing { - fn pack(self: T) -> felt252; - fn overflow_pack_protection(self: T) -> T; - fn unpack(packed: felt252) -> T; -} - -#[inline(always)] -fn rshift_split(value: u256, bits: u256) -> (u256, u256) { - integer::U256DivRem::div_rem(value, bits.try_into().expect('0 bits')) -} - -#[cfg(test)] -mod tests { - use super::rshift_split; - use pack::constants::pow; - - #[test] - #[available_gas(81450)] - fn test_rshift_split_pass() { - let v = 0b11010101; - - let (q, r) = rshift_split(v, pow::TWO_POW_1); - assert(q == 0b1101010, 'q 1 bit'); - assert(r == 0b1, 'r 1 bit'); - - let (q, r) = rshift_split(v, pow::TWO_POW_2); - assert(q == 0b110101, 'q 2 bits'); - assert(r == 0b01, 'r 2 bits'); - - let (q, r) = rshift_split(v, pow::TWO_POW_3); - assert(q == 0b11010, 'q 3 bits'); - assert(r == 0b101, 'r 3 bits'); - - let (q, r) = rshift_split(v, pow::TWO_POW_4); - assert(q == 0b1101, 'q 4 bits'); - assert(r == 0b0101, 'r 4 bits'); - - let (q, r) = rshift_split(v, pow::TWO_POW_8); - assert(q == 0, 'q 8 bits'); - assert(r == v, 'r 8 bits'); - } - - #[test] - #[available_gas(11750)] - #[should_panic] - fn test_rshift_split_0() { - rshift_split(0b1101, 0); - } -} From 7cbbe17328c918a3d07cdddad8c9afa72774cf0d Mon Sep 17 00:00:00 2001 From: loothero <100039621+loothero@users.noreply.github.com> Date: Sat, 30 Sep 2023 21:29:26 -0400 Subject: [PATCH 2/5] light refactoring (#374) * cleanup imports * cleanup comments --- contracts/adventurer/src/adventurer.cairo | 65 ++++----- .../adventurer/src/adventurer_meta.cairo | 4 +- .../adventurer/src/adventurer_stats.cairo | 28 ++-- .../adventurer/src/adventurer_utils.cairo | 18 ++- contracts/adventurer/src/bag.cairo | 25 ++-- contracts/adventurer/src/item_meta.cairo | 123 +++++++----------- contracts/adventurer/src/item_primitive.cairo | 21 ++- contracts/combat/src/combat.cairo | 12 +- contracts/loot/src/loot.cairo | 75 ++++++----- 9 files changed, 167 insertions(+), 204 deletions(-) diff --git a/contracts/adventurer/src/adventurer.cairo b/contracts/adventurer/src/adventurer.cairo index 0e4414141..a1efd9eb2 100644 --- a/contracts/adventurer/src/adventurer.cairo +++ b/contracts/adventurer/src/adventurer.cairo @@ -1,12 +1,11 @@ -use starknet::{StorePacking}; -use core::result::ResultTrait; -use core::integer::u256_try_as_non_zero; -use zeroable::NonZeroIntoImpl; -use integer::{u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub}; -use traits::{TryInto, Into}; -use option::OptionTrait; -use poseidon::poseidon_hash_span; -use array::ArrayTrait; +use core::{ + array::ArrayTrait, + integer::{u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, u256_try_as_non_zero}, + option::OptionTrait, + poseidon::poseidon_hash_span, + result::ResultTrait, starknet::{StorePacking}, + traits::{TryInto, Into} +}; use super::{ item_meta::{ItemSpecials, ItemSpecialsStorage, ImplItemSpecials}, @@ -60,25 +59,6 @@ struct Adventurer { mutated: bool, // not packed } -const TWO_POW_3: u256 = 0x8; -const TWO_POW_9: u256 = 0x200; -const TWO_POW_13: u256 = 0x2000; -const TWO_POW_18: u256 = 0x40000; -const TWO_POW_21: u256 = 0x200000; -const TWO_POW_30: u256 = 0x40000000; -const TWO_POW_31: u256 = 0x80000000; -const TWO_POW_61: u256 = 0x2000000000000000; -const TWO_POW_70: u256 = 0x400000000000000000; -const TWO_POW_91: u256 = 0x80000000000000000000000; -const TWO_POW_112: u256 = 0x10000000000000000000000000000; -const TWO_POW_133: u256 = 0x2000000000000000000000000000000000; -const TWO_POW_154: u256 = 0x400000000000000000000000000000000000000; -const TWO_POW_175: u256 = 0x80000000000000000000000000000000000000000000; -const TWO_POW_196: u256 = 0x10000000000000000000000000000000000000000000000000; -const TWO_POW_217: u256 = 0x2000000000000000000000000000000000000000000000000000000; -const TWO_POW_238: u256 = 0x400000000000000000000000000000000000000000000000000000000000; -const TWO_POW_247: u256 = 0x80000000000000000000000000000000000000000000000000000000000000; - impl AdventurerPacking of StorePacking { fn pack(value: Adventurer) -> felt252 { (value.last_action.into() @@ -985,7 +965,9 @@ impl ImplAdventurer of IAdventurer { hash_span.append(self.xp.into()); hash_span.append(adventurer_entropy.into()); let poseidon = poseidon_hash_span(hash_span.span()); - let (d, r) = integer::U256DivRem::div_rem(poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap()); + let (d, r) = integer::U256DivRem::div_rem( + poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); r.try_into().unwrap() } else { 0 @@ -1432,7 +1414,9 @@ impl ImplAdventurer of IAdventurer { hash_span.append(game_entropy.into()); let poseidon = poseidon_hash_span(hash_span.span()); - let (d, r) = integer::U256DivRem::div_rem(poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap()); + let (d, r) = integer::U256DivRem::div_rem( + poseidon.into(), u256_try_as_non_zero(U128_MAX.into()).unwrap() + ); return (r.try_into().unwrap(), d.try_into().unwrap()); } @@ -1694,6 +1678,25 @@ impl ImplAdventurer of IAdventurer { } } +const TWO_POW_3: u256 = 0x8; +const TWO_POW_9: u256 = 0x200; +const TWO_POW_13: u256 = 0x2000; +const TWO_POW_18: u256 = 0x40000; +const TWO_POW_21: u256 = 0x200000; +const TWO_POW_30: u256 = 0x40000000; +const TWO_POW_31: u256 = 0x80000000; +const TWO_POW_61: u256 = 0x2000000000000000; +const TWO_POW_70: u256 = 0x400000000000000000; +const TWO_POW_91: u256 = 0x80000000000000000000000; +const TWO_POW_112: u256 = 0x10000000000000000000000000000; +const TWO_POW_133: u256 = 0x2000000000000000000000000000000000; +const TWO_POW_154: u256 = 0x400000000000000000000000000000000000000; +const TWO_POW_175: u256 = 0x80000000000000000000000000000000000000000000; +const TWO_POW_196: u256 = 0x10000000000000000000000000000000000000000000000000; +const TWO_POW_217: u256 = 0x2000000000000000000000000000000000000000000000000000000; +const TWO_POW_238: u256 = 0x400000000000000000000000000000000000000000000000000000000000; +const TWO_POW_247: u256 = 0x80000000000000000000000000000000000000000000000000000000000000; + // --------------------------- // ---------- Tests ---------- // --------------------------- @@ -2794,7 +2797,7 @@ mod tests { 'stat_points_available' ); } - + #[test] #[available_gas(2000000)] fn test_new_adventurer() { diff --git a/contracts/adventurer/src/adventurer_meta.cairo b/contracts/adventurer/src/adventurer_meta.cairo index cadab6453..eace7e4df 100644 --- a/contracts/adventurer/src/adventurer_meta.cairo +++ b/contracts/adventurer/src/adventurer_meta.cairo @@ -7,8 +7,6 @@ struct AdventurerMetadata { entropy: u128, } -const TWO_POW_128: u256 = 0x100000000000000000000000000000000; - impl PackingAdventurerMetadata of StorePacking { fn pack(value: AdventurerMetadata) -> felt252 { (value.entropy.into() + value.name.into() * TWO_POW_128).try_into().unwrap() @@ -23,6 +21,8 @@ impl PackingAdventurerMetadata of StorePacking { } } +const TWO_POW_128: u256 = 0x100000000000000000000000000000000; + #[cfg(test)] #[test] #[available_gas(116600)] diff --git a/contracts/adventurer/src/adventurer_stats.cairo b/contracts/adventurer/src/adventurer_stats.cairo index 07bd7dc6b..7e5afa6f7 100644 --- a/contracts/adventurer/src/adventurer_stats.cairo +++ b/contracts/adventurer/src/adventurer_stats.cairo @@ -1,20 +1,14 @@ -use starknet::{StorePacking}; -use option::OptionTrait; -use traits::{TryInto, Into}; -use survivor::constants::adventurer_constants::MAX_STAT_VALUE; +use core::{option::OptionTrait, starknet::{StorePacking}, traits::{TryInto, Into}}; #[derive(Drop, Copy, Serde)] -struct Stats { // 5 bits each - // Physical +struct Stats { // 30 storage bits strength: u8, // 5 bits dexterity: u8, // 5 bits vitality: u8, // 5 bits - // Mental intelligence: u8, // 5 bits wisdom: u8, // 5 bits charisma: u8, // 5 bits - // Metaphysical - luck: u8 // // not stored - dynamically generated + luck: u8 // // dynamically generated, not stored. } #[generate_trait] @@ -26,12 +20,6 @@ impl StatUtils of IStat { } } -const TWO_POW_5: u256 = 0x20; -const TWO_POW_10: u256 = 0x400; -const TWO_POW_15: u256 = 0x8000; -const TWO_POW_20: u256 = 0x100000; -const TWO_POW_25: u256 = 0x2000000; - impl StatsPacking of StorePacking { fn pack(value: Stats) -> felt252 { (value.strength.into() @@ -73,14 +61,18 @@ impl StatsPacking of StorePacking { } } +const TWO_POW_5: u256 = 0x20; +const TWO_POW_10: u256 = 0x400; +const TWO_POW_15: u256 = 0x8000; +const TWO_POW_20: u256 = 0x100000; +const TWO_POW_25: u256 = 0x2000000; + // --------------------------- // ---------- Tests ---------- // --------------------------- #[cfg(test)] mod tests { - use survivor::{ - constants::adventurer_constants::MAX_STAT_VALUE, adventurer_stats::{Stats, StatsPacking} - }; + use survivor::adventurer_stats::{Stats, StatsPacking}; #[test] #[available_gas(1039260)] diff --git a/contracts/adventurer/src/adventurer_utils.cairo b/contracts/adventurer/src/adventurer_utils.cairo index 72745d736..2681e46be 100644 --- a/contracts/adventurer/src/adventurer_utils.cairo +++ b/contracts/adventurer/src/adventurer_utils.cairo @@ -1,10 +1,10 @@ -use core::array::SpanTrait; -use core::{result::ResultTrait, traits::{TryInto, Into}}; -use poseidon::poseidon_hash_span; -use option::OptionTrait; -use array::ArrayTrait; -use integer::{ - u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, U128IntoU256, u256_try_as_non_zero +use core::{ + array::{ArrayTrait, SpanTrait}, + integer::{ + u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, U128IntoU256, + u256_try_as_non_zero + }, + option::OptionTrait, poseidon::poseidon_hash_span, result::ResultTrait, traits::{TryInto, Into} }; use super::{ constants::{ @@ -30,9 +30,7 @@ use combat::constants::CombatEnums::{Type, Tier, Slot}; impl AdventurerUtils of IAdventurerUtils { // @dev Provides overflow protected stat increase. // This function protects against u8 overflow but allows stat - // to exceed MAX_STAT_VALUE as adventurers live stats are expected - // to exceed MAX_STAT_VALUE. Ensuring a stat does not overflow adventurer packing - // code is the responsibility of the adventurer packing code + // to exceed MAX_STAT_VALUE as adventurers live stats can exceed this threshold // @param current_stat The current value of the stat. // @param increase_amount The amount by which to increase the stat. // @return The increased stat value, or `MAX_STAT_VALUE` if an increase would cause an overflow. diff --git a/contracts/adventurer/src/bag.cairo b/contracts/adventurer/src/bag.cairo index b9623c387..adade6a4f 100644 --- a/contracts/adventurer/src/bag.cairo +++ b/contracts/adventurer/src/bag.cairo @@ -7,8 +7,7 @@ use super::{ }; // Bag is used for storing gear not equipped to the adventurer -// TODO: Change this to an Array with id: u8, size: u8, and modified: bool -// this will make the Bag more extensible and easier to work with in code +// Bag is a fixed size array of 11 items so it fits optimally in a felt252 #[derive(Drop, Copy, Serde)] struct Bag { item_1: ItemPrimitive, @@ -25,17 +24,6 @@ struct Bag { mutated: bool, } -const TWO_POW_21: u256 = 0x200000; -const TWO_POW_42: u256 = 0x40000000000; -const TWO_POW_63: u256 = 0x8000000000000000; -const TWO_POW_84: u256 = 0x1000000000000000000000; -const TWO_POW_105: u256 = 0x200000000000000000000000000; -const TWO_POW_126: u256 = 0x40000000000000000000000000000000; -const TWO_POW_147: u256 = 0x8000000000000000000000000000000000000; -const TWO_POW_168: u256 = 0x1000000000000000000000000000000000000000000; -const TWO_POW_189: u256 = 0x200000000000000000000000000000000000000000000000; -const TWO_POW_210: u256 = 0x40000000000000000000000000000000000000000000000000000; - impl BagPacking of StorePacking { fn pack(value: Bag) -> felt252 { (ItemPrimitivePacking::pack(value.item_1).into() @@ -376,6 +364,17 @@ impl ImplBag of IBag { } } +const TWO_POW_21: u256 = 0x200000; +const TWO_POW_42: u256 = 0x40000000000; +const TWO_POW_63: u256 = 0x8000000000000000; +const TWO_POW_84: u256 = 0x1000000000000000000000; +const TWO_POW_105: u256 = 0x200000000000000000000000000; +const TWO_POW_126: u256 = 0x40000000000000000000000000000000; +const TWO_POW_147: u256 = 0x8000000000000000000000000000000000000; +const TWO_POW_168: u256 = 0x1000000000000000000000000000000000000000000; +const TWO_POW_189: u256 = 0x200000000000000000000000000000000000000000000000; +const TWO_POW_210: u256 = 0x40000000000000000000000000000000000000000000000000000; + // --------------------------- // ---------- Tests ---------- // --------------------------- diff --git a/contracts/adventurer/src/item_meta.cairo b/contracts/adventurer/src/item_meta.cairo index 68c6add1e..840a9ae3b 100644 --- a/contracts/adventurer/src/item_meta.cairo +++ b/contracts/adventurer/src/item_meta.cairo @@ -5,39 +5,6 @@ use super::{ adventurer_stats::Stats, bag::{Bag, IBag} }; -mod STORAGE { - // First 10 indexes are stored in storage 1 - const INDEX_1: u8 = 1; - const INDEX_2: u8 = 2; - const INDEX_3: u8 = 3; - const INDEX_4: u8 = 4; - const INDEX_5: u8 = 5; - const INDEX_6: u8 = 6; - const INDEX_7: u8 = 7; - const INDEX_8: u8 = 8; - const INDEX_9: u8 = 9; - const INDEX_10: u8 = 10; - - // next 9 indexes are stored in storage 2 - const INDEX_11: u8 = 11; - const INDEX_12: u8 = 12; - const INDEX_13: u8 = 13; - const INDEX_14: u8 = 14; - const INDEX_15: u8 = 15; - const INDEX_16: u8 = 16; - const INDEX_17: u8 = 17; - const INDEX_18: u8 = 18; - const INDEX_19: u8 = 19; - - // make sure to update this if you add more storage slots - const MAX_TOTAL_STORAGE_SPECIALS: u8 = 19; - const MAX_SPECIALS_PER_STORAGE: u8 = 10; -} - -const MAX_SPECIAL1: u8 = 15; -const MAX_SPECIAL2: u8 = 127; -const MAX_SPECIAL3: u8 = 31; - #[derive(PartialEq, Drop, Copy, Serde)] struct ItemSpecials { special1: u8, // 4 bits in storage @@ -45,7 +12,7 @@ struct ItemSpecials { special3: u8, // 5 bits in storage } -// Player can have a total of 20 items. We map the items index to a slot in the metadata +// Fixed size to fit optimally in felt252 #[derive(Drop, Copy, Serde)] struct ItemSpecialsStorage { item_1: ItemSpecials, @@ -61,37 +28,6 @@ struct ItemSpecialsStorage { mutated: bool, } -// TODO: Meta data storage can be simplified and more easily extended by meta data storage by switching to the below -// data structure. This data structure will allow us to identify the storage id when -// it is being operated on and also to flag the storage as modified when it is altered -// so that the top-level contract code knows when it needs to write it to storage. -// currently the "has been modified" flows back down the stack in a relatively obscure way -// that results in a lot of code that is hard to follow and understand. This will make it -// much easier to follow and understand. Furthermore by using an array of structs we can -// make it easier to add more storage slots in the future. -// #[derive(Drop, Copy, Serde)] -// struct NewSpecialPowerStorage { -// id: u8, // provide storage id (1 or 2 for current game) -// size: u8, // size of the storage (10 for storage 1, 9 for storage 2 in current game) -// modified: bool, // a modified flag to make it easy to know when we need to write to storage -// item_specials: Array, -// } - -const TWO_POW_4: u256 = 0x10; -const TWO_POW_5: u256 = 0x20; -const TWO_POW_7: u256 = 0x80; -const TWO_POW_12: u256 = 0x1000; -const TWO_POW_16: u256 = 0x10000; // 2^16 -const TWO_POW_32: u256 = 0x100000000; // 2^32 -const TWO_POW_48: u256 = 0x1000000000000; // 2^48 -const TWO_POW_64: u256 = 0x10000000000000000; // 2^64 -const TWO_POW_80: u256 = 0x100000000000000000000; // 2^80 -const TWO_POW_96: u256 = 0x1000000000000000000000000; // 2^96 -const TWO_POW_112: u256 = 0x10000000000000000000000000000; // 2^112 -const TWO_POW_128: u256 = 0x100000000000000000000000000000000; // 2^128 -const TWO_POW_144: u256 = 0x1000000000000000000000000000000000000; // 2^144 - - impl ItemSpecialsPacking of StorePacking { fn pack(value: ItemSpecials) -> felt252 { (value.special2.into() @@ -174,16 +110,13 @@ impl ImplItemSpecials of IItemSpecials { fn get_specials(self: ItemSpecialsStorage, item: ItemPrimitive) -> ItemSpecials { // @dev Since this function doesn't know which name storage it has been given // it needs to consider both storage 1 and storage 2. In the current system - // which is relatively rigid (wip), name storage 1 is used for the first 10 items + // which is rigid because it's highly gas optimized, storage 1 is used for the first 10 items // and name storage 2 is used for the next 9 items. As such, if this function - // is called for an item with meta data is 1, it will be in the first slot of + // is called for an item with meta data 1, it will be in the first slot of // storage. Similarly, if this function is called with an item with meta data 11 // it will be in the first slot of storage 2. This is why we need to check for - // both storage 1 and storage 2. If we add more storage slots in the future - // we will need to update this function to check for those as well. - // I have a TODO at the top to restructure our ItemSpecialStorage struct to include - // an explicit storage id and size so we can provide a more flexible and robust - // solution to this problem. + // both storage 1 and storage 2. If you add more storage slots, you will need + // to update this function accordingly if item.metadata == STORAGE::INDEX_1 || item.metadata == STORAGE::INDEX_11 { self.item_1 } else if item.metadata == STORAGE::INDEX_2 || item.metadata == STORAGE::INDEX_12 { @@ -443,6 +376,49 @@ impl ImplItemSpecials of IItemSpecials { } } +mod STORAGE { + // First 10 indexes are stored in storage 1 + const INDEX_1: u8 = 1; + const INDEX_2: u8 = 2; + const INDEX_3: u8 = 3; + const INDEX_4: u8 = 4; + const INDEX_5: u8 = 5; + const INDEX_6: u8 = 6; + const INDEX_7: u8 = 7; + const INDEX_8: u8 = 8; + const INDEX_9: u8 = 9; + const INDEX_10: u8 = 10; + + // next 9 indexes are stored in storage 2 + const INDEX_11: u8 = 11; + const INDEX_12: u8 = 12; + const INDEX_13: u8 = 13; + const INDEX_14: u8 = 14; + const INDEX_15: u8 = 15; + const INDEX_16: u8 = 16; + const INDEX_17: u8 = 17; + const INDEX_18: u8 = 18; + const INDEX_19: u8 = 19; + + // make sure to update this if you add more storage slots + const MAX_TOTAL_STORAGE_SPECIALS: u8 = 19; + const MAX_SPECIALS_PER_STORAGE: u8 = 10; +} + +const TWO_POW_4: u256 = 0x10; +const TWO_POW_5: u256 = 0x20; +const TWO_POW_7: u256 = 0x80; +const TWO_POW_12: u256 = 0x1000; +const TWO_POW_16: u256 = 0x10000; +const TWO_POW_32: u256 = 0x100000000; +const TWO_POW_48: u256 = 0x1000000000000; +const TWO_POW_64: u256 = 0x10000000000000000; +const TWO_POW_80: u256 = 0x100000000000000000000; +const TWO_POW_96: u256 = 0x1000000000000000000000000; +const TWO_POW_112: u256 = 0x10000000000000000000000000000; +const TWO_POW_128: u256 = 0x100000000000000000000000000000000; +const TWO_POW_144: u256 = 0x1000000000000000000000000000000000000; + // --------------------------- // ---------- Tests ---------- // --------------------------- @@ -453,8 +429,7 @@ mod tests { adventurer::{ImplAdventurer}, item_primitive::ItemPrimitive, adventurer_stats::Stats, bag::{Bag, IBag}, item_meta::{ - ImplItemSpecials, ItemSpecialsStorage, ItemSpecials, ItemSpecialsStoragePacking, - MAX_SPECIAL1, MAX_SPECIAL2, MAX_SPECIAL3, STORAGE + ImplItemSpecials, ItemSpecialsStorage, ItemSpecials, ItemSpecialsStoragePacking, STORAGE }, }; diff --git a/contracts/adventurer/src/item_primitive.cairo b/contracts/adventurer/src/item_primitive.cairo index d36402645..e3f03eca8 100644 --- a/contracts/adventurer/src/item_primitive.cairo +++ b/contracts/adventurer/src/item_primitive.cairo @@ -1,24 +1,18 @@ -use starknet::{StorePacking}; -use option::OptionTrait; -use traits::{TryInto, Into}; +use core::{option::OptionTrait, starknet::StorePacking, traits::{TryInto, Into}}; use lootitems::loot::{ItemId}; -#[derive(Drop, Copy, PartialEq, Serde)] // 21 bits -struct ItemPrimitive { +#[derive(Drop, Copy, PartialEq, Serde)] +struct ItemPrimitive { // 21 storage bits id: u8, // 7 bits xp: u16, // 9 bits metadata: u8, // 5 bits } -const TWO_POW_5: u256 = 0x20; -const TWO_POW_7: u256 = 0x80; -const TWO_POW_9: u256 = 0x200; -const TWO_POW_16: u256 = 0x10000; - impl ItemPrimitivePacking of StorePacking { fn pack(value: ItemPrimitive) -> felt252 { (value.id.into() + value.xp.into() * TWO_POW_7 + value.metadata.into() * TWO_POW_16) - .try_into().unwrap() + .try_into() + .unwrap() } fn unpack(value: felt252) -> ItemPrimitive { @@ -68,6 +62,11 @@ impl ImplItemPrimitive of IItemPrimitive { } } +const TWO_POW_5: u256 = 0x20; +const TWO_POW_7: u256 = 0x80; +const TWO_POW_9: u256 = 0x200; +const TWO_POW_16: u256 = 0x10000; + // --------------------------- // ---------- Tests ---------- // --------------------------- diff --git a/contracts/combat/src/combat.cairo b/contracts/combat/src/combat.cairo index 743e7cff1..d94e13443 100644 --- a/contracts/combat/src/combat.cairo +++ b/contracts/combat/src/combat.cairo @@ -1,6 +1,4 @@ -use core::option::OptionTrait; -use integer::{u16_sqrt}; -use core::traits::{TryInto, Into, DivEq}; +use core::{integer::u16_sqrt, option::OptionTrait, traits::{TryInto, Into}}; use super::constants::{ CombatEnums::{Tier, Type, Slot, WeaponEffectiveness}, CombatSettings::{ @@ -10,7 +8,7 @@ use super::constants::{ } }; -// SpecialPowers contains special names for combat items +// For providing special item abilities #[derive(Drop, Copy, Serde)] struct SpecialPowers { special1: u8, @@ -18,7 +16,7 @@ struct SpecialPowers { special3: u8 } -// CombatSpec is used for performing combat calculations +// Used for combat calculations #[derive(Drop, Copy, Serde)] struct CombatSpec { tier: Tier, @@ -27,7 +25,7 @@ struct CombatSpec { specials: SpecialPowers, } -// CombatResult is used for providing combat results +// Used for providing combat results #[derive(Drop, Serde)] struct CombatResult { base_attack: u16, @@ -647,7 +645,7 @@ impl ImplCombat of ICombat { mod tests { use core::option::OptionTrait; use integer::{u16_sqrt}; - use core::traits::{TryInto, Into, DivEq}; + use core::traits::{TryInto, Into}; use combat::{ combat::{ImplCombat, ICombat, CombatSpec, SpecialPowers}, constants::{ diff --git a/contracts/loot/src/loot.cairo b/contracts/loot/src/loot.cairo index ff5ded1d8..eef1f3605 100644 --- a/contracts/loot/src/loot.cairo +++ b/contracts/loot/src/loot.cairo @@ -1,7 +1,6 @@ -use starknet::{StorePacking}; -use traits::{TryInto, Into}; -use option::OptionTrait; -use core::{serde::Serde, clone::Clone}; +use core::{ + serde::Serde, clone::Clone, option::OptionTrait, starknet::StorePacking, traits::{TryInto, Into} +}; use combat::{combat::ImplCombat, constants::CombatEnums::{Type, Tier, Slot}}; use super::{ @@ -26,6 +25,39 @@ struct Loot { slot: Slot, } +impl LootPacking of StorePacking { + fn pack(value: Loot) -> felt252 { + let item_tier = ImplCombat::tier_to_u8(value.tier); + let item_type = ImplCombat::type_to_u8(value.item_type); + let item_slot = ImplCombat::slot_to_u8(value.slot); + + (value.id.into() + + item_tier.into() * TWO_POW_8 + + item_type.into() * TWO_POW_16 + + item_slot.into() * TWO_POW_24) + .try_into() + .unwrap() + } + fn unpack(value: felt252) -> Loot { + let packed = value.into(); + let (packed, item_id) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); + let (packed, item_tier) = integer::U256DivRem::div_rem( + packed, TWO_POW_8.try_into().unwrap() + ); + let (packed, item_type) = integer::U256DivRem::div_rem( + packed, TWO_POW_8.try_into().unwrap() + ); + let (_, item_slot) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); + + Loot { + id: item_id.try_into().unwrap(), + tier: ImplCombat::u8_to_tier(item_tier.try_into().unwrap()), + item_type: ImplCombat::u8_to_type(item_type.try_into().unwrap()), + slot: ImplCombat::u8_to_slot(item_slot.try_into().unwrap()) + } + } +} + #[generate_trait] impl ImplLoot of ILoot { // generate_naming_seed generates a seed for naming an item. @@ -509,7 +541,7 @@ impl ImplLoot of ILoot { } } - // @notice getts the slot for a Loot item + // @notice gets the slot for a Loot item // @param id the id of the Loot item to get slot for // @return Slot the slot of the Loot item fn get_slot(id: u8) -> Slot { @@ -948,39 +980,6 @@ const TWO_POW_8: u256 = 0x100; const TWO_POW_16: u256 = 0x10000; const TWO_POW_24: u256 = 0x1000000; -impl LootPacking of StorePacking { - fn pack(value: Loot) -> felt252 { - let item_tier = ImplCombat::tier_to_u8(value.tier); - let item_type = ImplCombat::type_to_u8(value.item_type); - let item_slot = ImplCombat::slot_to_u8(value.slot); - - (value.id.into() - + item_tier.into() * TWO_POW_8 - + item_type.into() * TWO_POW_16 - + item_slot.into() * TWO_POW_24) - .try_into() - .unwrap() - } - fn unpack(value: felt252) -> Loot { - let packed = value.into(); - let (packed, item_id) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); - let (packed, item_tier) = integer::U256DivRem::div_rem( - packed, TWO_POW_8.try_into().unwrap() - ); - let (packed, item_type) = integer::U256DivRem::div_rem( - packed, TWO_POW_8.try_into().unwrap() - ); - let (_, item_slot) = integer::U256DivRem::div_rem(packed, TWO_POW_8.try_into().unwrap()); - - Loot { - id: item_id.try_into().unwrap(), - tier: ImplCombat::u8_to_tier(item_tier.try_into().unwrap()), - item_type: ImplCombat::u8_to_type(item_type.try_into().unwrap()), - slot: ImplCombat::u8_to_slot(item_slot.try_into().unwrap()) - } - } -} - // --------------------------- // ---------- Tests ---------- // --------------------------- From aa842e9148dff5f6123341edb366f6ec2a33b9d9 Mon Sep 17 00:00:00 2001 From: loothero Date: Sun, 1 Oct 2023 01:32:33 +0000 Subject: [PATCH 3/5] remove local scratchpad --- contracts/game/src/Scratchpad.txt | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 contracts/game/src/Scratchpad.txt diff --git a/contracts/game/src/Scratchpad.txt b/contracts/game/src/Scratchpad.txt deleted file mode 100644 index 6a5c45ad3..000000000 --- a/contracts/game/src/Scratchpad.txt +++ /dev/null @@ -1,17 +0,0 @@ -Scratchpad - -- Finished the market item duplicate bug --- I'm still not happy with the market item randomness as there is really only 6 market variants --- Need to figure out a way to pick 20 random numbers between 1-101 - -What do we need for mainnet? -- Jewlery -- Prevent equip when market is open to prevent players from putting all their + charisma gear on, buying items, then swapping back --- With this model, players who want to take advantage of their Charisma boosts will need to equip those items prior to leveling up which adds more difficulty -- Integrate Beasts ERC721 -- Code clean up / remove/complete all TODOs -- Add 60 more obstacles - -// Max action per turn - -// Jewlery Abilities From d1802d38b5cb2ab8f93fc34e5a6e63f12f7329b2 Mon Sep 17 00:00:00 2001 From: loothero <100039621+loothero@users.noreply.github.com> Date: Sat, 30 Sep 2023 23:28:21 -0400 Subject: [PATCH 4/5] Reduces storage slots for leaderboard from 6 to 1 (#375) * adds adventurers gold balance to leaderboard to serve as tie breaker ** tie breaker not implemented as part of this commit * adds view function for leaderboard --- contracts/adventurer/src/adventurer.cairo | 6 +- .../adventurer/src/adventurer_meta.cairo | 2 +- contracts/adventurer/src/leaderboard.cairo | 148 ++++++++++++++++++ contracts/adventurer/src/lib.cairo | 1 + contracts/game/src/game/interfaces.cairo | 6 +- contracts/game/src/lib.cairo | 121 +++++++------- 6 files changed, 220 insertions(+), 64 deletions(-) create mode 100644 contracts/adventurer/src/leaderboard.cairo diff --git a/contracts/adventurer/src/adventurer.cairo b/contracts/adventurer/src/adventurer.cairo index a1efd9eb2..d246fed7f 100644 --- a/contracts/adventurer/src/adventurer.cairo +++ b/contracts/adventurer/src/adventurer.cairo @@ -1,10 +1,8 @@ use core::{ array::ArrayTrait, integer::{u8_overflowing_add, u16_overflowing_add, u16_overflowing_sub, u256_try_as_non_zero}, - option::OptionTrait, - poseidon::poseidon_hash_span, - result::ResultTrait, starknet::{StorePacking}, - traits::{TryInto, Into} + option::OptionTrait, poseidon::poseidon_hash_span, result::ResultTrait, + starknet::{StorePacking}, traits::{TryInto, Into} }; use super::{ diff --git a/contracts/adventurer/src/adventurer_meta.cairo b/contracts/adventurer/src/adventurer_meta.cairo index eace7e4df..218803fa9 100644 --- a/contracts/adventurer/src/adventurer_meta.cairo +++ b/contracts/adventurer/src/adventurer_meta.cairo @@ -26,7 +26,7 @@ const TWO_POW_128: u256 = 0x100000000000000000000000000000000; #[cfg(test)] #[test] #[available_gas(116600)] -fn test_pack_unpack_adventurer_meta() { +fn test_adventurer_metadata_packing() { // max value case let max_u128 = 340282366920938463463374607431768211455; let name_length = 'abcdefghijklmno'; diff --git a/contracts/adventurer/src/leaderboard.cairo b/contracts/adventurer/src/leaderboard.cairo new file mode 100644 index 000000000..eb208b664 --- /dev/null +++ b/contracts/adventurer/src/leaderboard.cairo @@ -0,0 +1,148 @@ +use starknet::StorePacking; + +#[derive(Drop, Copy, Serde)] +struct Leaderboard { // 242 bits of storage + first: Score, // 83 bits + second: Score, // 83 bits + third: Score, // 83 bits +} + +#[derive(Drop, Copy, Serde)] +struct Score { // 83 bits of storage + adventurer_id: u64, // 61 bits + xp: u16, // 13 bits + gold: u16, // 9 bits +} + +impl ScorePacking of StorePacking { + fn pack(value: Score) -> felt252 { + (value.adventurer_id.into() + + (value.xp.into() * TWO_POW_61) + + (value.gold.into() * TWO_POW_74)) + .try_into() + .unwrap() + } + + fn unpack(value: felt252) -> Score { + let packed = value.into(); + let (packed, adventuer_id) = integer::U256DivRem::div_rem( + packed, TWO_POW_61.try_into().unwrap() + ); + let (packed, xp) = integer::U256DivRem::div_rem(packed, TWO_POW_13.try_into().unwrap()); + let (_, gold) = integer::U256DivRem::div_rem(packed, TWO_POW_9.try_into().unwrap()); + Score { + adventurer_id: adventuer_id.try_into().unwrap(), + xp: xp.try_into().unwrap(), + gold: gold.try_into().unwrap() + } + } +} + +impl LeaderboardPacking of StorePacking { + fn pack(value: Leaderboard) -> felt252 { + (ScorePacking::pack(value.first).into() + + (ScorePacking::pack(value.second).into() * TWO_POW_83) + + (ScorePacking::pack(value.third).into() * TWO_POW_166)) + .try_into() + .unwrap() + } + + fn unpack(value: felt252) -> Leaderboard { + let mut packed = value.into(); + let (packed, first) = integer::U256DivRem::div_rem(packed, TWO_POW_83.try_into().unwrap()); + let (packed, second) = integer::U256DivRem::div_rem(packed, TWO_POW_83.try_into().unwrap()); + let (packed, third) = integer::U256DivRem::div_rem(packed, TWO_POW_83.try_into().unwrap()); + + Leaderboard { + first: ScorePacking::unpack(first.try_into().unwrap()), + second: ScorePacking::unpack(second.try_into().unwrap()), + third: ScorePacking::unpack(third.try_into().unwrap()), + } + } +} + +const TWO_POW_9: u256 = 0x200; +const TWO_POW_13: u256 = 0x2000; +const TWO_POW_22: u256 = 0x400000; // 2^22 +const TWO_POW_44: u256 = 0x100000000000; // 2^44 +const TWO_POW_61: u256 = 0x2000000000000000; // 2^61 +const TWO_POW_66: u256 = 0x40000000000000000; // 2^66 +const TWO_POW_74: u256 = 0x4000000000000000000; // 2^74 +const TWO_POW_83: u256 = 0x800000000000000000000; // 2^83 +const TWO_POW_88: u256 = 0x10000000000000000000000; // 2^88 +const TWO_POW_110: u256 = 0x4000000000000000000000000000; // 2^110 +const TWO_POW_132: u256 = 0x1000000000000000000000000000000000; // 2^132 +const TWO_POW_154: u256 = 0x400000000000000000000000000000000000000; // 2^154 +const TWO_POW_166: u256 = 0x400000000000000000000000000000000000000000; // 2^166 +const TWO_POW_176: u256 = 0x100000000000000000000000000000000000000000000; // 2^176 +const TWO_POW_198: u256 = 0x40000000000000000000000000000000000000000000000000; // 2^198 +const TWO_POW_220: u256 = 0x10000000000000000000000000000000000000000000000000000000; // 2^220 + +// --------------------------- +// ---------- Tests ---------- +// --------------------------- +#[cfg(test)] +mod tests { + use survivor::leaderboard::{Score, ScorePacking, Leaderboard, LeaderboardPacking}; + + #[test] + #[available_gas(201560)] + fn test_score_packing() { + // max value case + let max_adventurer_id = 2305843009213693951; + let max_xp = 8191; + let max_gold = 511; + + let score = Score { adventurer_id: max_adventurer_id, xp: max_xp, gold: max_gold }; + let packed = ScorePacking::pack(score); + let unpacked: Score = ScorePacking::unpack(packed); + assert(unpacked.xp == score.xp, 'xp should be max'); + assert(unpacked.gold == score.gold, 'gold should be max'); + + // zero case + let score = Score { adventurer_id: 0, xp: 0, gold: 0 }; + let packed = ScorePacking::pack(score); + let unpacked: Score = ScorePacking::unpack(packed); + assert(unpacked.xp == score.xp, 'xp should be 0'); + assert(unpacked.gold == score.gold, 'gold should be 0'); + } + + #[test] + #[available_gas(425830)] + fn test_leaderboard_packing() { + // max value case + let max_adventurer_id = 2305843009213693951; + let max_xp = 8191; + let max_gold = 511; + + let leaderboard = Leaderboard { + first: Score { adventurer_id: max_adventurer_id, xp: max_xp, gold: max_gold }, + second: Score { + adventurer_id: max_adventurer_id - 1, xp: max_xp - 1, gold: max_gold - 1 + }, + third: Score { + adventurer_id: max_adventurer_id - 2, xp: max_xp - 2, gold: max_gold - 2 + }, + }; + let packed = LeaderboardPacking::pack(leaderboard); + let unpacked: Leaderboard = LeaderboardPacking::unpack(packed); + assert( + unpacked.first.adventurer_id == leaderboard.first.adventurer_id, + 'wrong first adventurer_id' + ); + assert(unpacked.first.xp == leaderboard.first.xp, 'wrong first xp'); + assert(unpacked.first.gold == leaderboard.first.gold, 'wrong first gold'); + assert( + unpacked.second.adventurer_id == leaderboard.second.adventurer_id, + 'wrong second adventurer_id' + ); + assert(unpacked.second.xp == leaderboard.second.xp, 'wrong second xp'); + assert(unpacked.second.gold == leaderboard.second.gold, 'wrong second gold'); + assert( + unpacked.third.adventurer_id == leaderboard.third.adventurer_id, + 'wrong third adventurer_id' + ); + assert(unpacked.third.xp == leaderboard.third.xp, 'wrong third xp'); + assert(unpacked.third.gold == leaderboard.third.gold, 'wrong third gold'); + } +} diff --git a/contracts/adventurer/src/lib.cairo b/contracts/adventurer/src/lib.cairo index c3ea5655c..d5badffd7 100644 --- a/contracts/adventurer/src/lib.cairo +++ b/contracts/adventurer/src/lib.cairo @@ -10,3 +10,4 @@ mod constants { mod discovery_constants; mod adventurer_constants; } +mod leaderboard; \ No newline at end of file diff --git a/contracts/game/src/game/interfaces.cairo b/contracts/game/src/game/interfaces.cairo index ff6cadff3..d1fc181a4 100644 --- a/contracts/game/src/game/interfaces.cairo +++ b/contracts/game/src/game/interfaces.cairo @@ -3,7 +3,8 @@ use market::market::{ItemPurchase}; use beasts::beast::Beast; use survivor::{ bag::Bag, adventurer::{Adventurer, Stats}, adventurer_meta::AdventurerMetadata, - item_meta::{ItemSpecials, ItemSpecialsStorage} + item_meta::{ItemSpecials, ItemSpecialsStorage}, + leaderboard::Leaderboard, }; use game::game::game_entropy::{GameEntropy}; @@ -111,4 +112,5 @@ trait IGame { fn get_dao_address(self: @TContractState) -> ContractAddress; fn get_lords_address(self: @TContractState) -> ContractAddress; fn get_game_entropy(self: @TContractState) -> GameEntropy; -} + fn get_leaderboard(self: @TContractState) -> Leaderboard; +} \ No newline at end of file diff --git a/contracts/game/src/lib.cairo b/contracts/game/src/lib.cairo index e0a128951..f9b204f72 100644 --- a/contracts/game/src/lib.cairo +++ b/contracts/game/src/lib.cairo @@ -12,7 +12,7 @@ mod Game { // TODO: TESTING CONFIGS // ADJUST THESE BEFORE DEPLOYMENT const TEST_ENTROPY: u64 = 12303548; - const MINIMUM_SCORE_FOR_PAYOUTS: u256 = 100; + const MINIMUM_SCORE_FOR_PAYOUTS: u16 = 100; const LOOT_NAME_STORAGE_INDEX_1: u256 = 0; const LOOT_NAME_STORAGE_INDEX_2: u256 = 1; @@ -54,7 +54,7 @@ mod Game { } }, item_meta::{ImplItemSpecials, ItemSpecials, IItemSpecials, ItemSpecialsStorage}, - adventurer_utils::AdventurerUtils + adventurer_utils::AdventurerUtils, leaderboard::{Score, Leaderboard}, }; use market::{ market::{ImplMarket, LootWithPrice, ItemPurchase}, constants::{NUMBER_OF_ITEMS_PER_LEVEL} @@ -67,20 +67,18 @@ mod Game { #[storage] struct Storage { - _game_entropy: GameEntropy, _adventurer: LegacyMap::, - _owner: LegacyMap::, _adventurer_meta: LegacyMap::, - _item_specials: LegacyMap::<(u256, u256), ItemSpecialsStorage>, _bag: LegacyMap::, - _counter: u256, - _lords: ContractAddress, - _dao: ContractAddress, _collectible_beasts: ContractAddress, - // 1,2,3 // Survivor ID - _scoreboard: LegacyMap::, - _scores: LegacyMap::, + _dao: ContractAddress, + _game_counter: u256, + _game_entropy: GameEntropy, _genesis_block: u64, + _leaderboard: Leaderboard, + _lords: ContractAddress, + _owner: LegacyMap::, + _item_specials: LegacyMap::<(u256, u256), ItemSpecialsStorage>, } #[event] @@ -817,6 +815,9 @@ mod Game { fn get_game_entropy(self: @ContractState) -> GameEntropy { _unpack_game_entropy(self) } + fn get_leaderboard(self: @ContractState) -> Leaderboard { + self._leaderboard.read() + } fn owner_of(self: @ContractState, adventurer_id: u256) -> ContractAddress { _owner_of(self, adventurer_id) } @@ -955,7 +956,7 @@ mod Game { __event_AdventurerDied(ref self, AdventurerDied { adventurer_state, death_details }); if _is_top_score(@self, adventurer.xp) { - _update_leaderboard(ref self, adventurer_state); + _update_leaderboard(ref self, adventurer_id, adventurer); } } @@ -973,15 +974,13 @@ mod Game { let genesis_block = self._genesis_block.read(); let dao_address = self._dao.read(); - let first_place_adventurer_id = self._scoreboard.read(1); - let first_place_address = self._owner.read(first_place_adventurer_id); - let second_place_adventurer_id = self._scoreboard.read(2); - let second_place_address = self._owner.read(second_place_adventurer_id); - let third_place_adventurer_id = self._scoreboard.read(3); - let third_place_address = self._owner.read(third_place_adventurer_id); + let leaderboard = self._leaderboard.read(); + let first_place_address = self._owner.read(leaderboard.first.adventurer_id.into()); + let second_place_address = self._owner.read(leaderboard.second.adventurer_id.into()); + let third_place_address = self._owner.read(leaderboard.third.adventurer_id.into()); // if third place score is less than minimum score for payouts - if (self._scores.read(3) < MINIMUM_SCORE_FOR_PAYOUTS) { + if (leaderboard.third.xp < MINIMUM_SCORE_FOR_PAYOUTS) { // all rewards go to the DAO // the purpose of this is to let a decent set of top scores get set before payouts begin // without this, there would be an incentive to start and die immediately after contract is deployed @@ -1069,19 +1068,19 @@ mod Game { ref self, RewardDistribution { first_place: PlayerReward { - adventurer_id: first_place_adventurer_id, + adventurer_id: leaderboard.first.adventurer_id.into(), rank: 1, amount: week.FIRST_PLACE, address: first_place_address }, second_place: PlayerReward { - adventurer_id: second_place_adventurer_id, + adventurer_id: leaderboard.second.adventurer_id.into(), rank: 2, amount: week.SECOND_PLACE, address: second_place_address }, third_place: PlayerReward { - adventurer_id: third_place_adventurer_id, + adventurer_id: leaderboard.third.adventurer_id.into(), rank: 3, amount: week.THIRD_PLACE, address: third_place_address @@ -1094,7 +1093,7 @@ mod Game { fn _start_game(ref self: ContractState, weapon: u8, name: u128) { // increment adventurer id (first adventurer is id 1) - let adventurer_id = self._counter.read() + 1; + let adventurer_id = self._game_counter.read() + 1; // use current starknet block number and timestamp as entropy sources let block_number = starknet::get_block_info().unbox().block_number; @@ -1126,7 +1125,7 @@ mod Game { _pack_adventurer_meta(ref self, adventurer_id, adventurer_meta); // increment the adventurer id counter - self._counter.write(adventurer_id); + self._game_counter.write(adventurer_id); // set caller as owner self._owner.write(adventurer_id, get_caller_address()); @@ -2439,52 +2438,55 @@ mod Game { (_get_adventurer_entropy(self, adventurer_id), _unpack_game_entropy(self).entropy) } - #[inline(always)] - fn _get_score_for_adventurer(self: @ContractState, adventurer_id: u256) -> u256 { - self._scores.read(adventurer_id) - } - #[inline(always)] fn _is_top_score(self: @ContractState, score: u16) -> bool { - if score.into() > self._scores.read(3) { + if score > self._leaderboard.read().third.xp { true } else { false } } + // @title Update Leaderboard Function + // + // @param adventurer_id The unique identifier of the adventurer + // @param adventurer The adventurer that scored a new high score + fn _update_leaderboard(ref self: ContractState, adventurer_id: u256, adventurer: Adventurer) { + // get current leaderboard which will be mutated as part of this function + let mut leaderboard = self._leaderboard.read(); - // sets the scoreboard - // we set the adventurer id in the scoreboard as we already store the owners address - fn _update_leaderboard(ref self: ContractState, adventurer_state: AdventurerState) { - let score = adventurer_state.adventurer.xp; - let second_place = self._scoreboard.read(2); - let first_place = self._scoreboard.read(1); + // create a score struct for the players score + let player_score = Score { + adventurer_id: adventurer_id.try_into().unwrap(), + xp: adventurer.xp, + gold: adventurer.gold + }; + + let mut player_rank = 0; - if score.into() > self._scores.read(1) { - __event_NewHighScore(ref self, adventurer_state, 1); - self._scoreboard.write(3, second_place); - self._scoreboard.write(2, first_place); - self._scoreboard.write(1, adventurer_state.adventurer_id); - self._scores.write(3, self._scores.read(2)); - self._scores.write(2, self._scores.read(1)); - self._scores.write(1, score.into()); - } else if score.into() > self._scores.read(2) { - __event_NewHighScore(ref self, adventurer_state, 2); - self._scoreboard.write(3, second_place); - self._scoreboard.write(2, adventurer_state.adventurer_id); - self._scores.write(3, self._scores.read(2)); - self._scores.write(2, score.into()); - } else if score.into() > self._scores.read(3) { - __event_NewHighScore(ref self, adventurer_state, 3); - self._scoreboard.write(3, adventurer_state.adventurer_id); - self._scores.write(3, score.into()); + // shift leaderboard based on players placement + if player_score.xp > leaderboard.first.xp { + leaderboard.third = leaderboard.second; + leaderboard.second = leaderboard.first; + leaderboard.first = player_score; + player_rank = 1; + } else if player_score.xp > leaderboard.second.xp { + leaderboard.third = leaderboard.second; + leaderboard.second = player_score; + player_rank = 2; + } else if player_score.xp > leaderboard.third.xp { + leaderboard.third = player_score; + player_rank = 3; } - } + // emit new high score event + __event_NewHighScore(ref self, adventurer_id, adventurer, player_rank); - // EVENTS ------------------------------------ // + // save leaderboard + self._leaderboard.write(leaderboard); + } + // ---------- EVENTS ---------- // #[derive(Copy, Drop, Serde, starknet::Event)] struct AdventurerState { owner: ContractAddress, @@ -2981,7 +2983,12 @@ mod Game { self.emit(ItemsLeveledUp { adventurer_state, items }); } - fn __event_NewHighScore(ref self: ContractState, adventurer_state: AdventurerState, rank: u8) { + fn __event_NewHighScore( + ref self: ContractState, adventurer_id: u256, adventurer: Adventurer, rank: u8 + ) { + let adventurer_state = AdventurerState { + owner: get_caller_address(), adventurer_id, adventurer + }; self.emit(NewHighScore { adventurer_state, rank }); } From 77ce76c9a758be200b534a0456e791c67cf79039 Mon Sep 17 00:00:00 2001 From: loothero <100039621+loothero@users.noreply.github.com> Date: Sun, 1 Oct 2023 00:11:37 -0400 Subject: [PATCH 5/5] change adventurer id from u256 to felt252 (#376) * total gas from contract tests reduced by 26.71% --- .../adventurer/src/adventurer_utils.cairo | 8 +- contracts/game/src/game/interfaces.cairo | 117 ++++---- contracts/game/src/lib.cairo | 268 +++++++++--------- contracts/game/src/tests/test_game.cairo | 2 +- contracts/market/src/market.cairo | 2 +- 5 files changed, 205 insertions(+), 192 deletions(-) diff --git a/contracts/adventurer/src/adventurer_utils.cairo b/contracts/adventurer/src/adventurer_utils.cairo index 2681e46be..29474fdc2 100644 --- a/contracts/adventurer/src/adventurer_utils.cairo +++ b/contracts/adventurer/src/adventurer_utils.cairo @@ -83,10 +83,10 @@ impl AdventurerUtils of IAdventurerUtils { // @param adventurer_id The ID of the adventurer used in generating the entropy // @return A u128 type entropy unique to the block number and adventurer ID fn generate_adventurer_entropy( - adventurer_id: u256, block_number: u64, block_timestamp: u64 + adventurer_id: felt252, block_number: u64, block_timestamp: u64 ) -> u128 { let mut hash_span = ArrayTrait::::new(); - hash_span.append(adventurer_id.try_into().unwrap()); + hash_span.append(adventurer_id); hash_span.append(block_number.into()); hash_span.append(block_timestamp.into()); let poseidon: felt252 = poseidon_hash_span(hash_span.span()).into(); @@ -549,12 +549,12 @@ mod tests { #[test] #[available_gas(6482260)] fn test_generate_adventurer_entropy() { - let mut i: u256 = 1; + let mut i: u8 = 1; loop { if (i >= 100) { break; } - let adventurer_id: u256 = i; + let adventurer_id = i.into(); let block_number = 839152; let block_timestamp = 53289712; let adventurer_entropy = AdventurerUtils::generate_adventurer_entropy( diff --git a/contracts/game/src/game/interfaces.cairo b/contracts/game/src/game/interfaces.cairo index d1fc181a4..33a7a6091 100644 --- a/contracts/game/src/game/interfaces.cairo +++ b/contracts/game/src/game/interfaces.cairo @@ -3,8 +3,7 @@ use market::market::{ItemPurchase}; use beasts::beast::Beast; use survivor::{ bag::Bag, adventurer::{Adventurer, Stats}, adventurer_meta::AdventurerMetadata, - item_meta::{ItemSpecials, ItemSpecialsStorage}, - leaderboard::Leaderboard, + item_meta::{ItemSpecials, ItemSpecialsStorage}, leaderboard::Leaderboard, }; use game::game::game_entropy::{GameEntropy}; @@ -15,92 +14,92 @@ trait IGame { fn new_game( ref self: TContractState, client_reward_address: ContractAddress, weapon: u8, name: u128 ); - fn explore(ref self: TContractState, adventurer_id: u256, till_beast: bool); - fn attack(ref self: TContractState, adventurer_id: u256, to_the_death: bool); - fn flee(ref self: TContractState, adventurer_id: u256, to_the_death: bool); - fn equip(ref self: TContractState, adventurer_id: u256, items: Array); - fn drop(ref self: TContractState, adventurer_id: u256, items: Array); + fn explore(ref self: TContractState, adventurer_id: felt252, till_beast: bool); + fn attack(ref self: TContractState, adventurer_id: felt252, to_the_death: bool); + fn flee(ref self: TContractState, adventurer_id: felt252, to_the_death: bool); + fn equip(ref self: TContractState, adventurer_id: felt252, items: Array); + fn drop(ref self: TContractState, adventurer_id: felt252, items: Array); fn upgrade( ref self: TContractState, - adventurer_id: u256, + adventurer_id: felt252, potions: u8, stat_upgrades: Stats, items: Array, ); - fn slay_idle_adventurers(ref self: TContractState, adventurer_ids: Array); + fn slay_idle_adventurers(ref self: TContractState, adventurer_ids: Array); fn rotate_game_entropy(ref self: TContractState); // ------ View Functions ------ // adventurer details - fn get_adventurer(self: @TContractState, adventurer_id: u256) -> Adventurer; - fn get_adventurer_no_boosts(self: @TContractState, adventurer_id: u256) -> Adventurer; - fn get_adventurer_meta(self: @TContractState, adventurer_id: u256) -> AdventurerMetadata; - fn get_health(self: @TContractState, adventurer_id: u256) -> u16; - fn get_xp(self: @TContractState, adventurer_id: u256) -> u16; - fn get_level(self: @TContractState, adventurer_id: u256) -> u8; - fn get_gold(self: @TContractState, adventurer_id: u256) -> u16; - fn get_stat_upgrades_available(self: @TContractState, adventurer_id: u256) -> u8; - fn get_last_action(self: @TContractState, adventurer_id: u256) -> u16; + fn get_adventurer(self: @TContractState, adventurer_id: felt252) -> Adventurer; + fn get_adventurer_no_boosts(self: @TContractState, adventurer_id: felt252) -> Adventurer; + fn get_adventurer_meta(self: @TContractState, adventurer_id: felt252) -> AdventurerMetadata; + fn get_health(self: @TContractState, adventurer_id: felt252) -> u16; + fn get_xp(self: @TContractState, adventurer_id: felt252) -> u16; + fn get_level(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_gold(self: @TContractState, adventurer_id: felt252) -> u16; + fn get_stat_upgrades_available(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_last_action(self: @TContractState, adventurer_id: felt252) -> u16; // adventurer stats (includes boost) - fn get_stats(self: @TContractState, adventurer_id: u256) -> Stats; - fn get_strength(self: @TContractState, adventurer_id: u256) -> u8; - fn get_dexterity(self: @TContractState, adventurer_id: u256) -> u8; - fn get_vitality(self: @TContractState, adventurer_id: u256) -> u8; - fn get_intelligence(self: @TContractState, adventurer_id: u256) -> u8; - fn get_wisdom(self: @TContractState, adventurer_id: u256) -> u8; - fn get_charisma(self: @TContractState, adventurer_id: u256) -> u8; + fn get_stats(self: @TContractState, adventurer_id: felt252) -> Stats; + fn get_strength(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_dexterity(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_vitality(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_intelligence(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_wisdom(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_charisma(self: @TContractState, adventurer_id: felt252) -> u8; // item stats - fn get_weapon_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_chest_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_head_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_waist_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_foot_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_hand_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_necklace_greatness(self: @TContractState, adventurer_id: u256) -> u8; - fn get_ring_greatness(self: @TContractState, adventurer_id: u256) -> u8; + fn get_weapon_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_chest_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_head_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_waist_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_foot_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_hand_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_necklace_greatness(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_ring_greatness(self: @TContractState, adventurer_id: felt252) -> u8; // bag and specials - fn get_bag(self: @TContractState, adventurer_id: u256) -> Bag; + fn get_bag(self: @TContractState, adventurer_id: felt252) -> Bag; fn get_special_storage( - self: @TContractState, adventurer_id: u256, storage_index: u256 + self: @TContractState, adventurer_id: felt252, storage_index: u8 ) -> ItemSpecialsStorage; // item details - fn get_weapon_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_chest_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_head_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_waist_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_foot_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_hand_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_necklace_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; - fn get_ring_specials(self: @TContractState, adventurer_id: u256) -> ItemSpecials; + fn get_weapon_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_chest_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_head_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_waist_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_foot_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_hand_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_necklace_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; + fn get_ring_specials(self: @TContractState, adventurer_id: felt252) -> ItemSpecials; // market details - fn get_items_on_market(self: @TContractState, adventurer_id: u256) -> Array; + fn get_items_on_market(self: @TContractState, adventurer_id: felt252) -> Array; fn get_items_on_market_by_slot( - self: @TContractState, adventurer_id: u256, slot: u8 + self: @TContractState, adventurer_id: felt252, slot: u8 ) -> Array; fn get_items_on_market_by_tier( - self: @TContractState, adventurer_id: u256, tier: u8 + self: @TContractState, adventurer_id: felt252, tier: u8 ) -> Array; - fn get_potion_price(self: @TContractState, adventurer_id: u256) -> u16; - fn get_item_price(self: @TContractState, adventurer_id: u256, item_id: u8) -> u16; + fn get_potion_price(self: @TContractState, adventurer_id: felt252) -> u16; + fn get_item_price(self: @TContractState, adventurer_id: felt252, item_id: u8) -> u16; // adventurer stats (no boosts) - fn get_base_stats(self: @TContractState, adventurer_id: u256) -> Stats; - fn get_base_strength(self: @TContractState, adventurer_id: u256) -> u8; - fn get_base_dexterity(self: @TContractState, adventurer_id: u256) -> u8; - fn get_base_vitality(self: @TContractState, adventurer_id: u256) -> u8; - fn get_base_intelligence(self: @TContractState, adventurer_id: u256) -> u8; - fn get_base_wisdom(self: @TContractState, adventurer_id: u256) -> u8; - fn get_base_charisma(self: @TContractState, adventurer_id: u256) -> u8; + fn get_base_stats(self: @TContractState, adventurer_id: felt252) -> Stats; + fn get_base_strength(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_base_dexterity(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_base_vitality(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_base_intelligence(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_base_wisdom(self: @TContractState, adventurer_id: felt252) -> u8; + fn get_base_charisma(self: @TContractState, adventurer_id: felt252) -> u8; // beast details - fn get_attacking_beast(self: @TContractState, adventurer_id: u256) -> Beast; - fn get_beast_health(self: @TContractState, adventurer_id: u256) -> u16; + fn get_attacking_beast(self: @TContractState, adventurer_id: felt252) -> Beast; + fn get_beast_health(self: @TContractState, adventurer_id: felt252) -> u16; fn get_beast_type(self: @TContractState, beast_id: u8) -> u8; fn get_beast_tier(self: @TContractState, beast_id: u8) -> u8; @@ -108,9 +107,9 @@ trait IGame { fn next_game_entropy_rotation(self: @TContractState) -> felt252; // contract details - fn owner_of(self: @TContractState, adventurer_id: u256) -> ContractAddress; + fn owner_of(self: @TContractState, adventurer_id: felt252) -> ContractAddress; fn get_dao_address(self: @TContractState) -> ContractAddress; fn get_lords_address(self: @TContractState) -> ContractAddress; fn get_game_entropy(self: @TContractState) -> GameEntropy; fn get_leaderboard(self: @TContractState) -> Leaderboard; -} \ No newline at end of file +} diff --git a/contracts/game/src/lib.cairo b/contracts/game/src/lib.cairo index f9b204f72..88d10cd96 100644 --- a/contracts/game/src/lib.cairo +++ b/contracts/game/src/lib.cairo @@ -13,8 +13,8 @@ mod Game { // ADJUST THESE BEFORE DEPLOYMENT const TEST_ENTROPY: u64 = 12303548; const MINIMUM_SCORE_FOR_PAYOUTS: u16 = 100; - const LOOT_NAME_STORAGE_INDEX_1: u256 = 0; - const LOOT_NAME_STORAGE_INDEX_2: u256 = 1; + const LOOT_NAME_STORAGE_INDEX_1: u8 = 0; + const LOOT_NAME_STORAGE_INDEX_2: u8 = 1; use core::{ array::{SpanTrait, ArrayTrait}, integer::u256_try_as_non_zero, traits::{TryInto, Into}, @@ -67,18 +67,18 @@ mod Game { #[storage] struct Storage { - _adventurer: LegacyMap::, - _adventurer_meta: LegacyMap::, - _bag: LegacyMap::, + _adventurer: LegacyMap::, + _adventurer_meta: LegacyMap::, + _bag: LegacyMap::, _collectible_beasts: ContractAddress, _dao: ContractAddress, - _game_counter: u256, + _game_counter: felt252, _game_entropy: GameEntropy, _genesis_block: u64, _leaderboard: Leaderboard, _lords: ContractAddress, - _owner: LegacyMap::, - _item_specials: LegacyMap::<(u256, u256), ItemSpecialsStorage>, + _owner: LegacyMap::, + _item_specials: LegacyMap::<(felt252, u8), ItemSpecialsStorage>, } #[event] @@ -162,7 +162,7 @@ mod Game { /// /// @param adventurer_id A u256 representing the ID of the adventurer. /// @param till_beast A boolean flag indicating if the exploration continues until encountering a beast. - fn explore(ref self: ContractState, adventurer_id: u256, till_beast: bool) { + fn explore(ref self: ContractState, adventurer_id: felt252, till_beast: bool) { // get adventurer from storage with stat boosts applied let (mut adventurer, stat_boosts, _) = _unpack_adventurer_and_bag_with_stat_boosts( @self, adventurer_id @@ -214,7 +214,7 @@ mod Game { /// /// @param adventurer_id A u256 representing the ID of the adventurer. /// @param to_the_death A boolean flag indicating if the attack should continue until either the adventurer or the beast is defeated. - fn attack(ref self: ContractState, adventurer_id: u256, to_the_death: bool) { + fn attack(ref self: ContractState, adventurer_id: felt252, to_the_death: bool) { // get adventurer from storage with stat boosts applied let (mut adventurer, stat_boosts, _) = _unpack_adventurer_and_bag_with_stat_boosts( @self, adventurer_id @@ -287,7 +287,7 @@ mod Game { /// /// @param adventurer_id A u256 representing the unique ID of the adventurer. /// @param to_the_death A boolean flag indicating if the flee attempt should continue until either the adventurer escapes or is defeated. - fn flee(ref self: ContractState, adventurer_id: u256, to_the_death: bool) { + fn flee(ref self: ContractState, adventurer_id: felt252, to_the_death: bool) { // get adventurer from storage with stat boosts applied let (mut adventurer, stat_boosts, _) = _unpack_adventurer_and_bag_with_stat_boosts( @self, adventurer_id @@ -353,7 +353,7 @@ mod Game { /// /// @param adventurer_id A u256 representing the unique ID of the adventurer. /// @param items A u8 array representing the item IDs to equip. - fn equip(ref self: ContractState, adventurer_id: u256, items: Array) { + fn equip(ref self: ContractState, adventurer_id: felt252, items: Array) { // get adventurer and bag from storage with stat boosts applied let (mut adventurer, stat_boosts, mut bag) = _unpack_adventurer_and_bag_with_stat_boosts( @@ -415,7 +415,7 @@ mod Game { /// /// @param adventurer_id A u256 representing the unique ID of the adventurer. /// @param items A u8 Array representing the IDs of the items to drop. - fn drop(ref self: ContractState, adventurer_id: u256, items: Array) { + fn drop(ref self: ContractState, adventurer_id: felt252, items: Array) { // get adventurer and bag from storage with stat boosts applied let (mut adventurer, stat_boosts, mut bag) = _unpack_adventurer_and_bag_with_stat_boosts( @@ -456,7 +456,7 @@ mod Game { /// @param items An array of ItemPurchase detailing the items the adventurer wishes to purchase during the upgrade. fn upgrade( ref self: ContractState, - adventurer_id: u256, + adventurer_id: felt252, potions: u8, stat_upgrades: Stats, items: Array, @@ -529,7 +529,7 @@ mod Game { /// @notice Allows anyone to slay idle adventurers /// /// @param adventurer_ids: A u256 array representing the IDs of adventurers to slay - fn slay_idle_adventurers(ref self: ContractState, adventurer_ids: Array) { + fn slay_idle_adventurers(ref self: ContractState, adventurer_ids: Array) { let mut adventurer_index: u32 = 0; loop { if adventurer_index == adventurer_ids.len() { @@ -553,54 +553,54 @@ mod Game { // // view functions // - fn get_adventurer(self: @ContractState, adventurer_id: u256) -> Adventurer { + fn get_adventurer(self: @ContractState, adventurer_id: felt252) -> Adventurer { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer } - fn get_adventurer_no_boosts(self: @ContractState, adventurer_id: u256) -> Adventurer { + fn get_adventurer_no_boosts(self: @ContractState, adventurer_id: felt252) -> Adventurer { _unpack_adventurer(self, adventurer_id) } - fn get_adventurer_meta(self: @ContractState, adventurer_id: u256) -> AdventurerMetadata { + fn get_adventurer_meta(self: @ContractState, adventurer_id: felt252) -> AdventurerMetadata { _unpack_adventurer_meta(self, adventurer_id) } - fn get_bag(self: @ContractState, adventurer_id: u256) -> Bag { + fn get_bag(self: @ContractState, adventurer_id: felt252) -> Bag { _unpacked_bag(self, adventurer_id) } - fn get_weapon_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_weapon_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.weapon) } - fn get_chest_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_chest_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.chest) } - fn get_head_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_head_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.head) } - fn get_waist_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_waist_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.waist) } - fn get_foot_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_foot_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.foot) } - fn get_hand_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_hand_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.hand) } - fn get_necklace_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_necklace_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.neck) } - fn get_ring_specials(self: @ContractState, adventurer_id: u256) -> ItemSpecials { + fn get_ring_specials(self: @ContractState, adventurer_id: felt252) -> ItemSpecials { let adventurer = _unpack_adventurer(self, adventurer_id); _get_item_specials(self, adventurer_id, adventurer.ring) } - fn get_items_on_market(self: @ContractState, adventurer_id: u256) -> Array { + fn get_items_on_market(self: @ContractState, adventurer_id: felt252) -> Array { let adventurer = _unpack_adventurer(self, adventurer_id); _assert_upgrades_available(adventurer); let adventurer_entropy: u128 = _unpack_adventurer_meta(self, adventurer_id) @@ -611,7 +611,7 @@ mod Game { ) } fn get_items_on_market_by_slot( - self: @ContractState, adventurer_id: u256, slot: u8 + self: @ContractState, adventurer_id: felt252, slot: u8 ) -> Array { let adventurer = _unpack_adventurer(self, adventurer_id); _assert_upgrades_available(adventurer); @@ -627,7 +627,7 @@ mod Game { ) } fn get_items_on_market_by_tier( - self: @ContractState, adventurer_id: u256, tier: u8 + self: @ContractState, adventurer_id: felt252, tier: u8 ) -> Array { let adventurer = _unpack_adventurer(self, adventurer_id); _assert_upgrades_available(adventurer); @@ -678,125 +678,125 @@ mod Game { } } - fn get_potion_price(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_potion_price(self: @ContractState, adventurer_id: felt252) -> u16 { _get_potion_price(self, adventurer_id) } - fn get_item_price(self: @ContractState, adventurer_id: u256, item_id: u8) -> u16 { + fn get_item_price(self: @ContractState, adventurer_id: felt252, item_id: u8) -> u16 { _get_item_price(self, adventurer_id, item_id) } - fn get_attacking_beast(self: @ContractState, adventurer_id: u256) -> Beast { + fn get_attacking_beast(self: @ContractState, adventurer_id: felt252) -> Beast { _get_attacking_beast(self, adventurer_id) } - fn get_health(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_health(self: @ContractState, adventurer_id: felt252) -> u16 { _unpack_adventurer(self, adventurer_id).health } - fn get_xp(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_xp(self: @ContractState, adventurer_id: felt252) -> u16 { _unpack_adventurer(self, adventurer_id).xp } - fn get_level(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_level(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).get_level() } - fn get_gold(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_gold(self: @ContractState, adventurer_id: felt252) -> u16 { _unpack_adventurer(self, adventurer_id).gold } - fn get_beast_health(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_beast_health(self: @ContractState, adventurer_id: felt252) -> u16 { _unpack_adventurer(self, adventurer_id).beast_health } - fn get_stat_upgrades_available(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_stat_upgrades_available(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stat_points_available } - fn get_last_action(self: @ContractState, adventurer_id: u256) -> u16 { + fn get_last_action(self: @ContractState, adventurer_id: felt252) -> u16 { _unpack_adventurer(self, adventurer_id).last_action } - fn get_weapon_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_weapon_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).weapon.get_greatness() } - fn get_chest_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_chest_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).chest.get_greatness() } - fn get_head_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_head_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).head.get_greatness() } - fn get_waist_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_waist_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).waist.get_greatness() } - fn get_foot_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_foot_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).foot.get_greatness() } - fn get_hand_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_hand_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).hand.get_greatness() } - fn get_necklace_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_necklace_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).neck.get_greatness() } - fn get_ring_greatness(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_ring_greatness(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).ring.get_greatness() } - fn get_base_stats(self: @ContractState, adventurer_id: u256) -> Stats { + fn get_base_stats(self: @ContractState, adventurer_id: felt252) -> Stats { _unpack_adventurer(self, adventurer_id).stats } - fn get_stats(self: @ContractState, adventurer_id: u256) -> Stats { + fn get_stats(self: @ContractState, adventurer_id: felt252) -> Stats { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats } - fn get_base_strength(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_strength(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.strength } - fn get_strength(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_strength(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.strength } - fn get_base_dexterity(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_dexterity(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.dexterity } - fn get_dexterity(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_dexterity(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.dexterity } - fn get_base_vitality(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_vitality(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.vitality } - fn get_vitality(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_vitality(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.vitality } - fn get_base_intelligence(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_intelligence(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.intelligence } - fn get_intelligence(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_intelligence(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.intelligence } - fn get_base_wisdom(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_wisdom(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.wisdom } - fn get_wisdom(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_wisdom(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.wisdom } - fn get_base_charisma(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_base_charisma(self: @ContractState, adventurer_id: felt252) -> u8 { _unpack_adventurer(self, adventurer_id).stats.charisma } - fn get_charisma(self: @ContractState, adventurer_id: u256) -> u8 { + fn get_charisma(self: @ContractState, adventurer_id: felt252) -> u8 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts( self, adventurer_id ); adventurer.stats.charisma } fn get_special_storage( - self: @ContractState, adventurer_id: u256, storage_index: u256 + self: @ContractState, adventurer_id: felt252, storage_index: u8 ) -> ItemSpecialsStorage { self._item_specials.read((adventurer_id, storage_index)) } @@ -818,7 +818,7 @@ mod Game { fn get_leaderboard(self: @ContractState) -> Leaderboard { self._leaderboard.read() } - fn owner_of(self: @ContractState, adventurer_id: u256) -> ContractAddress { + fn owner_of(self: @ContractState, adventurer_id: felt252) -> ContractAddress { _owner_of(self, adventurer_id) } fn next_game_entropy_rotation(self: @ContractState) -> felt252 { @@ -830,7 +830,7 @@ mod Game { // ------------ Internal Functions ---------- // // ------------------------------------------ // - fn _slay_idle_adventurer(ref self: ContractState, adventurer_id: u256) { + fn _slay_idle_adventurer(ref self: ContractState, adventurer_id: felt252) { // unpack adventurer from storage (no need for stat boosts) let mut adventurer = _unpack_adventurer(@self, adventurer_id); @@ -853,7 +853,7 @@ mod Game { fn _process_beast_death( ref self: ContractState, ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast: Beast, beast_seed: u128, attack_rnd_2: u128, @@ -939,7 +939,7 @@ mod Game { fn _process_adventurer_death( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast_id: u8, obstacle_id: u8 ) { @@ -1133,7 +1133,7 @@ mod Game { fn _starter_beast_ambush( ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, starting_weapon: u8, adventurer_entropy: u128 ) -> BattleDetails { @@ -1163,11 +1163,11 @@ mod Game { // _explore is called by the adventurer to explore the world // @param self: ContractState // @param adventurer: Adventurer - // @param adventurer_id: u256 + // @param adventurer_id: felt252 fn _explore( ref self: ContractState, ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, adventurer_entropy: u128, game_entropy: u128, explore_till_beast: bool @@ -1209,7 +1209,7 @@ mod Game { } fn _process_discovery( - ref self: ContractState, ref adventurer: Adventurer, adventurer_id: u256, entropy: u128 + ref self: ContractState, ref adventurer: Adventurer, adventurer_id: felt252, entropy: u128 ) { // TODO: Consider passing in adventurer ref into discover_treasure and handling // adventurer mutations within lib functions. The lib functions could return @@ -1243,7 +1243,7 @@ mod Game { ref self: ContractState, ref adventurer: Adventurer, adventurer_entropy: u128, - adventurer_id: u256, + adventurer_id: felt252, entropy: u128 ) { // get beast and beast seed @@ -1273,7 +1273,7 @@ mod Game { } fn _obstacle_encounter( - ref self: ContractState, ref adventurer: Adventurer, adventurer_id: u256, entropy: u128 + ref self: ContractState, ref adventurer: Adventurer, adventurer_id: felt252, entropy: u128 ) { // get random obstacle let obstacle = adventurer.get_random_obstacle(entropy); @@ -1367,7 +1367,7 @@ mod Game { fn _grant_xp_to_equipped_items( ref self: ContractState, ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, xp_amount: u16, entropy: u128 ) -> Array { @@ -1490,7 +1490,7 @@ mod Game { ref self: ContractState, ref adventurer: Adventurer, weapon_combat_spec: CombatSpec, - adventurer_id: u256, + adventurer_id: felt252, adventurer_entropy: u128, beast: Beast, beast_seed: u128, @@ -1583,7 +1583,7 @@ mod Game { fn _beast_attack( ref self: ContractState, ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast: Beast, beast_seed: u128, entropy: u128, @@ -1628,7 +1628,7 @@ mod Game { fn _flee( ref self: ContractState, ref adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, adventurer_entropy: u128, game_entropy: u128, beast_seed: u128, @@ -1727,7 +1727,7 @@ mod Game { ref self: ContractState, ref adventurer: Adventurer, ref bag: Bag, - adventurer_id: u256, + adventurer_id: felt252, items_to_equip: Array, is_newly_purchased: bool ) { @@ -1792,7 +1792,7 @@ mod Game { ref self: ContractState, ref adventurer: Adventurer, ref bag: Bag, - adventurer_id: u256, + adventurer_id: felt252, items: Array, ) { // for each item @@ -1830,7 +1830,7 @@ mod Game { ref self: ContractState, ref adventurer: Adventurer, ref bag: Bag, - adventurer_id: u256, + adventurer_id: felt252, stat_points_available: u8, items_to_purchase: Array, ) { @@ -1892,7 +1892,7 @@ mod Game { // @dev Emits a `PurchasedPotions` event // @dev Panics if the adventurer does not have enough gold or is buying more health than they can use. fn _buy_potions( - ref self: ContractState, ref adventurer: Adventurer, adventurer_id: u256, quantity: u8 + ref self: ContractState, ref adventurer: Adventurer, adventurer_id: felt252, quantity: u8 ) { let cost = adventurer.charisma_adjusted_potion_price() * quantity.into(); let health = POTION_HEALTH_AMOUNT * quantity.into(); @@ -1980,16 +1980,19 @@ mod Game { // ------------------------------------------ // // ------------ Helper Functions ------------ // // ------------------------------------------ // - fn _unpack_adventurer(self: @ContractState, adventurer_id: u256) -> Adventurer { - self._adventurer.read(adventurer_id) + fn _unpack_adventurer(self: @ContractState, adventurer_id: felt252) -> Adventurer { + let adventurer = self._adventurer.read(adventurer_id); + adventurer } fn _unpack_adventurer_and_bag_with_stat_boosts( - self: @ContractState, adventurer_id: u256 + self: @ContractState, adventurer_id: felt252 ) -> (Adventurer, Stats, Bag) { // unpack adventurer let mut adventurer: Adventurer = self._adventurer.read(adventurer_id); + // start with no stat boosts let mut stat_boosts = StatUtils::new(); + // if adventurer has item specials if adventurer.has_item_specials() { // get specials from storage @@ -2000,6 +2003,7 @@ mod Game { adventurer.apply_stat_boosts(stat_boosts); } + // get bag from storage let bag = _unpacked_bag(self, adventurer_id); // luck isn't stored, it is calculated dynamically @@ -2010,7 +2014,7 @@ mod Game { } #[inline(always)] - fn _pack_adventurer(ref self: ContractState, adventurer_id: u256, adventurer: Adventurer) { + fn _pack_adventurer(ref self: ContractState, adventurer_id: felt252, adventurer: Adventurer) { self._adventurer.write(adventurer_id, adventurer); } // @dev Packs and saves an adventurer after removing stat boosts. @@ -2018,7 +2022,10 @@ mod Game { // @param adventurer The adventurer to be modified. // @param stat_boosts The stat boosts to be removed. fn _pack_adventurer_remove_stat_boost( - ref self: ContractState, ref adventurer: Adventurer, adventurer_id: u256, stat_boosts: Stats + ref self: ContractState, + ref adventurer: Adventurer, + adventurer_id: felt252, + stat_boosts: Stats ) { // remove stat boosts adventurer.remove_stat_boosts(stat_boosts); @@ -2028,20 +2035,20 @@ mod Game { } #[inline(always)] - fn _unpacked_bag(self: @ContractState, adventurer_id: u256) -> Bag { + fn _unpacked_bag(self: @ContractState, adventurer_id: felt252) -> Bag { self._bag.read(adventurer_id) } #[inline(always)] - fn _pack_bag(ref self: ContractState, adventurer_id: u256, bag: Bag) { + fn _pack_bag(ref self: ContractState, adventurer_id: felt252, bag: Bag) { self._bag.write(adventurer_id, bag); } #[inline(always)] - fn _unpack_adventurer_meta(self: @ContractState, adventurer_id: u256) -> AdventurerMetadata { + fn _unpack_adventurer_meta(self: @ContractState, adventurer_id: felt252) -> AdventurerMetadata { self._adventurer_meta.read(adventurer_id) } #[inline(always)] fn _pack_adventurer_meta( - ref self: ContractState, adventurer_id: u256, adventurer_meta: AdventurerMetadata + ref self: ContractState, adventurer_id: felt252, adventurer_meta: AdventurerMetadata ) { self._adventurer_meta.write(adventurer_id, adventurer_meta); } @@ -2098,7 +2105,7 @@ mod Game { fn _emit_level_up_events( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, previous_level: u8, new_level: u8, ) { @@ -2122,8 +2129,8 @@ mod Game { #[inline(always)] fn _pack_loot_special_names_storage( ref self: ContractState, - adventurer_id: u256, - storage_index: u256, + adventurer_id: felt252, + storage_index: u8, loot_special_names_storage: ItemSpecialsStorage, ) { self._item_specials.write((adventurer_id, storage_index), loot_special_names_storage); @@ -2131,7 +2138,7 @@ mod Game { #[inline(always)] fn _get_special_storages( - self: @ContractState, adventurer_id: u256 + self: @ContractState, adventurer_id: felt252 ) -> (ItemSpecialsStorage, ItemSpecialsStorage) { ( _get_specials_storage(self, adventurer_id, LOOT_NAME_STORAGE_INDEX_1), @@ -2141,14 +2148,14 @@ mod Game { #[inline(always)] fn _get_specials_storage( - self: @ContractState, adventurer_id: u256, storage_index: u256 + self: @ContractState, adventurer_id: felt252, storage_index: u8 ) -> ItemSpecialsStorage { self._item_specials.read((adventurer_id, storage_index)) } #[inline(always)] fn _get_item_specials( - self: @ContractState, adventurer_id: u256, item: ItemPrimitive + self: @ContractState, adventurer_id: felt252, item: ItemPrimitive ) -> ItemSpecials { if (item.get_greatness() >= 15) { ImplItemSpecials::get_specials( @@ -2160,14 +2167,14 @@ mod Game { } } #[inline(always)] - fn _owner_of(self: @ContractState, adventurer_id: u256) -> ContractAddress { + fn _owner_of(self: @ContractState, adventurer_id: felt252) -> ContractAddress { self._owner.read(adventurer_id) } #[inline(always)] fn _next_game_entropy_rotation(self: @ContractState) -> felt252 { _unpack_game_entropy(self).last_updated.into() + MIN_BLOCKS_FOR_GAME_ENTROPY_CHANGE.into() } - fn _assert_ownership(self: @ContractState, adventurer_id: u256) { + fn _assert_ownership(self: @ContractState, adventurer_id: felt252) { assert(self._owner.read(adventurer_id) == get_caller_address(), messages::NOT_OWNER); } fn _assert_in_battle(adventurer: Adventurer) { @@ -2278,7 +2285,10 @@ mod Game { // while this may seem harsh, Loot Survivor is modeled after an arcade game. You can't // walk away from a game of Galaga for 10 minutes and come back expecting to still be alive fn _apply_idle_penalty( - ref self: ContractState, adventurer_id: u256, ref adventurer: Adventurer, idle_blocks: u16 + ref self: ContractState, + adventurer_id: felt252, + ref adventurer: Adventurer, + idle_blocks: u16 ) { // deduct it from adventurer's health adventurer.health = 0; @@ -2333,12 +2343,12 @@ mod Game { } #[inline(always)] - fn _get_potion_price(self: @ContractState, adventurer_id: u256) -> u16 { + fn _get_potion_price(self: @ContractState, adventurer_id: felt252) -> u16 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts(self, adventurer_id); adventurer.charisma_adjusted_potion_price() } - fn _get_item_price(self: @ContractState, adventurer_id: u256, item_id: u8) -> u16 { + fn _get_item_price(self: @ContractState, adventurer_id: felt252, item_id: u8) -> u16 { let (adventurer, _, _) = _unpack_adventurer_and_bag_with_stat_boosts(self, adventurer_id); let base_item_price = ImplMarket::get_price(ImplLoot::get_tier(item_id)); let charisma_adjusted_price = adventurer.charisma_adjusted_item_price(base_item_price); @@ -2346,7 +2356,7 @@ mod Game { charisma_adjusted_price } - fn _get_attacking_beast(self: @ContractState, adventurer_id: u256) -> Beast { + fn _get_attacking_beast(self: @ContractState, adventurer_id: felt252) -> Beast { // get adventurer let adventurer = _unpack_adventurer(self, adventurer_id); @@ -2364,7 +2374,7 @@ mod Game { } #[inline(always)] - fn _get_storage_index(self: @ContractState, meta_data_id: u8) -> u256 { + fn _get_storage_index(self: @ContractState, meta_data_id: u8) -> u8 { if (meta_data_id <= 10) { LOOT_NAME_STORAGE_INDEX_1 } else { @@ -2377,7 +2387,7 @@ mod Game { // @param adventurer_id - the id of the adventurer // @param item - the item to get the combat spec for fn _get_combat_spec( - self: @ContractState, adventurer_id: u256, item: ItemPrimitive + self: @ContractState, adventurer_id: felt252, item: ItemPrimitive ) -> CombatSpec { // if item is 0, return a default combat spec if (item.id == 0) { @@ -2425,7 +2435,7 @@ mod Game { } #[inline(always)] - fn _get_adventurer_entropy(self: @ContractState, adventurer_id: u256) -> u128 { + fn _get_adventurer_entropy(self: @ContractState, adventurer_id: felt252) -> u128 { _unpack_adventurer_meta(self, adventurer_id).entropy } @@ -2434,7 +2444,9 @@ mod Game { // @param adventurer_id - the id of the adventurer // @return (u128, u64) - adventurer entropy and game entropy #[inline(always)] - fn _get_adventurer_and_game_entropy(self: @ContractState, adventurer_id: u256) -> (u128, u128) { + fn _get_adventurer_and_game_entropy( + self: @ContractState, adventurer_id: felt252 + ) -> (u128, u128) { (_get_adventurer_entropy(self, adventurer_id), _unpack_game_entropy(self).entropy) } @@ -2451,7 +2463,9 @@ mod Game { // // @param adventurer_id The unique identifier of the adventurer // @param adventurer The adventurer that scored a new high score - fn _update_leaderboard(ref self: ContractState, adventurer_id: u256, adventurer: Adventurer) { + fn _update_leaderboard( + ref self: ContractState, adventurer_id: felt252, adventurer: Adventurer + ) { // get current leaderboard which will be mutated as part of this function let mut leaderboard = self._leaderboard.read(); @@ -2490,7 +2504,7 @@ mod Game { #[derive(Copy, Drop, Serde, starknet::Event)] struct AdventurerState { owner: ContractAddress, - adventurer_id: u256, + adventurer_id: felt252, adventurer: Adventurer } @@ -2729,7 +2743,7 @@ mod Game { #[derive(Drop, Serde)] struct PlayerReward { - adventurer_id: u256, + adventurer_id: felt252, rank: u8, amount: u256, address: ContractAddress, @@ -2748,7 +2762,7 @@ mod Game { fn __event_AdventurerUpgraded( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, bag: Bag, stat_upgrades: Stats ) { @@ -2773,7 +2787,7 @@ mod Game { fn __event_StartGame( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, adventurer_meta: AdventurerMetadata ) { let adventurer_state = AdventurerState { @@ -2785,7 +2799,7 @@ mod Game { fn __event_Discovery( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, amount: u16, discovery_type: DiscoveryType ) { @@ -2808,7 +2822,7 @@ mod Game { fn __event_ObstacleEncounter( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, dodged: bool, obstacle_details: ObstacleDetails, ) { @@ -2828,7 +2842,7 @@ mod Game { fn __event_DiscoveredBeast( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, seed: u128, beast: Beast ) { @@ -2845,7 +2859,7 @@ mod Game { fn __event_AttackedBeast( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast_battle_details: BattleDetails ) { let adventurer_state = AdventurerState { @@ -2857,7 +2871,7 @@ mod Game { fn __event_AttackedByBeast( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast_battle_details: BattleDetails ) { let adventurer_state = AdventurerState { @@ -2869,7 +2883,7 @@ mod Game { fn __event_AmbushedByBeast( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, beast_battle_details: BattleDetails ) { let adventurer_state = AdventurerState { @@ -2881,7 +2895,7 @@ mod Game { fn __event_SlayedBeast( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, seed: u128, beast: Beast, damage_dealt: u16, @@ -2910,7 +2924,7 @@ mod Game { fn __event_FleeFailed( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, seed: u128, beast: Beast ) { @@ -2926,7 +2940,7 @@ mod Game { fn __event_FleeSucceeded( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, seed: u128, beast: Beast ) { @@ -2942,7 +2956,7 @@ mod Game { fn __event_EquippedItems( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, bag: Bag, equipped_items: Array, unequipped_items: Array, @@ -2960,7 +2974,7 @@ mod Game { fn __event_DroppedItems( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, bag: Bag, item_ids: Array, ) { @@ -2974,7 +2988,7 @@ mod Game { fn __event_ItemsLeveledUp( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, items: Array, ) { let adventurer_state = AdventurerState { @@ -2984,7 +2998,7 @@ mod Game { } fn __event_NewHighScore( - ref self: ContractState, adventurer_id: u256, adventurer: Adventurer, rank: u8 + ref self: ContractState, adventurer_id: felt252, adventurer: Adventurer, rank: u8 ) { let adventurer_state = AdventurerState { owner: get_caller_address(), adventurer_id, adventurer @@ -3006,7 +3020,7 @@ mod Game { } fn __event_IdleDeathPenalty( - ref self: ContractState, adventurer: Adventurer, adventurer_id: u256, idle_blocks: u16, + ref self: ContractState, adventurer: Adventurer, adventurer_id: felt252, idle_blocks: u16, ) { // intentionally read storage for owner instead of using get_caller_address() // because non-owner can result in this function being emitted via `slay_idle_adventurer` @@ -3033,7 +3047,7 @@ mod Game { fn __event_PurchasedItems( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, bag: Bag, purchases: Array ) { @@ -3047,7 +3061,7 @@ mod Game { fn __event_PurchasedPotions( ref self: ContractState, adventurer: Adventurer, - adventurer_id: u256, + adventurer_id: felt252, quantity: u8, cost: u16, health: u16 diff --git a/contracts/game/src/tests/test_game.cairo b/contracts/game/src/tests/test_game.cairo index ecaee9f4b..a6a98b1b6 100644 --- a/contracts/game/src/tests/test_game.cairo +++ b/contracts/game/src/tests/test_game.cairo @@ -50,7 +50,7 @@ mod tests { contract_address_const::<1>() } - const ADVENTURER_ID: u256 = 1; + const ADVENTURER_ID: felt252 = 1; const MAX_LORDS: u256 = 500000000000000000000; const APPROVE: u256 = 50000000000000000000; diff --git a/contracts/market/src/market.cairo b/contracts/market/src/market.cairo index e668ad535..8a5b90d9d 100644 --- a/contracts/market/src/market.cairo +++ b/contracts/market/src/market.cairo @@ -580,7 +580,7 @@ mod tests { if (i == 100) { break; } - let adventurer_id: u256 = 1; + let adventurer_id: felt252 = 1; let block_number = 839152; let xp: u16 = 3; let stats_points_available: u8 = 4;