Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

update packing #546

Merged
merged 3 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions contracts/adventurer/Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "beasts"
version = "0.1.0"
dependencies = [
"combat",
]

[[package]]
name = "combat"
version = "0.1.0"

[[package]]
name = "lootitems"
version = "0.1.0"
dependencies = [
"combat",
]

[[package]]
name = "market"
version = "0.1.0"
dependencies = [
"combat",
"lootitems",
]

[[package]]
name = "obstacles"
version = "0.1.0"
dependencies = [
"combat",
]

[[package]]
name = "survivor"
version = "0.1.0"
dependencies = [
"beasts",
"combat",
"lootitems",
"market",
"obstacles",
]
124 changes: 74 additions & 50 deletions contracts/adventurer/src/adventurer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use super::{
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, MAX_ACTIONS_PER_BLOCK, MAX_PACKABLE_ITEM_XP,
MAX_PACKABLE_BEAST_HEALTH, MAX_LAST_ACTION_BLOCK
MAX_PACKABLE_BEAST_HEALTH, MAX_LAST_ACTION_BLOCK, MAX_STAT_VALUE_5_BITS
},
discovery_constants::DiscoveryEnums::{ExploreResult, DiscoveryType}
},
Expand All @@ -43,8 +43,8 @@ use beasts::{beast::{ImplBeast, Beast}, constants::BeastSettings};
struct Adventurer {
last_action_block: u16, // 9 bits
health: u16, // 9 bits
xp: u16, // 13 bits
stats: Stats, // 24 bits
xp: u16, // 14 bits
stats: Stats, // 26 bits
gold: u16, // 9 bits
weapon: ItemPrimitive, // 21 bits
chest: ItemPrimitive, // 21 bits
Expand All @@ -67,31 +67,32 @@ impl AdventurerPacking of StorePacking<Adventurer, felt252> {
(value.last_action_block.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_55
+ ItemPrimitivePacking::pack(value.weapon).into() * TWO_POW_64
+ ItemPrimitivePacking::pack(value.chest).into() * TWO_POW_85
+ ItemPrimitivePacking::pack(value.head).into() * TWO_POW_106
+ ItemPrimitivePacking::pack(value.waist).into() * TWO_POW_127
+ ItemPrimitivePacking::pack(value.foot).into() * TWO_POW_148
+ ItemPrimitivePacking::pack(value.hand).into() * TWO_POW_169
+ ItemPrimitivePacking::pack(value.neck).into() * TWO_POW_190
+ ItemPrimitivePacking::pack(value.ring).into() * TWO_POW_211
+ value.beast_health.into() * TWO_POW_232
+ value.stat_points_available.into() * TWO_POW_241
+ value.actions_per_block.into() * TWO_POW_244)
+ StatsPacking::pack(value.stats).into() * TWO_POW_32
+ value.gold.into() * TWO_POW_58
+ ItemPrimitivePacking::pack(value.weapon).into() * TWO_POW_67
+ ItemPrimitivePacking::pack(value.chest).into() * TWO_POW_88
+ ItemPrimitivePacking::pack(value.head).into() * TWO_POW_109
+ ItemPrimitivePacking::pack(value.waist).into() * TWO_POW_130
+ ItemPrimitivePacking::pack(value.foot).into() * TWO_POW_151
+ ItemPrimitivePacking::pack(value.hand).into() * TWO_POW_172
+ ItemPrimitivePacking::pack(value.neck).into() * TWO_POW_193
+ ItemPrimitivePacking::pack(value.ring).into() * TWO_POW_214
+ value.beast_health.into() * TWO_POW_235
+ value.stat_points_available.into() * TWO_POW_244
+ value.actions_per_block.into() * TWO_POW_247)
.try_into()
.unwrap()
}


fn unpack(value: felt252) -> Adventurer {
let packed = value.into();
let (packed, last_action_block) = 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_24.try_into().unwrap());
let (packed, xp) = integer::U256DivRem::div_rem(packed, TWO_POW_14.try_into().unwrap());
let (packed, stats) = integer::U256DivRem::div_rem(packed, TWO_POW_26.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());
Expand Down Expand Up @@ -128,7 +129,7 @@ impl AdventurerPacking of StorePacking<Adventurer, felt252> {
beast_health: beast_health.try_into().unwrap(),
stat_points_available: stat_points_available.try_into().unwrap(),
actions_per_block: actions_per_block.try_into().unwrap(),
mutated: false,
mutated: false, // This field is not packed/unpacked
}
}
}
Expand Down Expand Up @@ -1669,9 +1670,9 @@ impl ImplAdventurer of IAdventurer {
assert(self.health <= MAX_ADVENTURER_HEALTH, 'health overflow');
assert(self.xp <= MAX_XP, 'xp overflow');
assert(self.gold <= MAX_GOLD, 'gold overflow');
assert(self.stats.strength <= MAX_STAT_VALUE, 'strength overflow');
assert(self.stats.strength <= MAX_STAT_VALUE_5_BITS, 'strength overflow');
assert(self.stats.dexterity <= MAX_STAT_VALUE, 'dexterity overflow');
assert(self.stats.vitality <= MAX_STAT_VALUE, 'vitality overflow');
assert(self.stats.vitality <= MAX_STAT_VALUE_5_BITS, 'vitality overflow');
assert(self.stats.charisma <= MAX_STAT_VALUE, 'charisma overflow');
assert(self.stats.intelligence <= MAX_STAT_VALUE, 'intelligence overflow');
assert(self.stats.wisdom <= MAX_STAT_VALUE, 'wisdom overflow');
Expand Down Expand Up @@ -1702,26 +1703,31 @@ impl ImplAdventurer of IAdventurer {
}
}

const TWO_POW_3: u256 = 0x8;
const TWO_POW_4: u256 = 0x10;
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_24: u256 = 0x1000000;
const TWO_POW_31: u256 = 0x80000000;
const TWO_POW_55: u256 = 0x80000000000000;
const TWO_POW_64: u256 = 0x10000000000000000;
const TWO_POW_85: u256 = 0x2000000000000000000000;
const TWO_POW_106: u256 = 0x400000000000000000000000000;
const TWO_POW_127: u256 = 0x80000000000000000000000000000000;
const TWO_POW_148: u256 = 0x10000000000000000000000000000000000000;
const TWO_POW_169: u256 = 0x2000000000000000000000000000000000000000000;
const TWO_POW_190: u256 = 0x400000000000000000000000000000000000000000000000;
const TWO_POW_211: u256 = 0x80000000000000000000000000000000000000000000000000000;
const TWO_POW_232: u256 = 0x10000000000000000000000000000000000000000000000000000000000;
const TWO_POW_241: u256 = 0x2000000000000000000000000000000000000000000000000000000000000;
const TWO_POW_244: u256 = 0x10000000000000000000000000000000000000000000000000000000000000;

const TWO_POW_3: u256 = 0x8; // 2^3
const TWO_POW_4: u256 = 0x10; // 2^4
const TWO_POW_9: u256 = 0x200; // 2^9
const TWO_POW_13: u256 = 0x2000; // 2^13
const TWO_POW_14: u256 = 0x4000; // 2^14
const TWO_POW_18: u256 = 0x40000; // 2^18
const TWO_POW_21: u256 = 0x200000; // 2^21
const TWO_POW_26: u256 = 0x4000000; // 2^26
const TWO_POW_27: u256 = 0x8000000; // 2^27
const TWO_POW_31: u256 = 0x80000000; // 2^31
const TWO_POW_32: u256 = 0x100000000; // 2^32
const TWO_POW_58: u256 = 0x400000000000000; // 2^58
const TWO_POW_67: u256 = 0x80000000000000000; // 2^67
const TWO_POW_88: u256 = 0x10000000000000000000000; // 2^88
const TWO_POW_109: u256 = 0x2000000000000000000000000000; // 2^109
const TWO_POW_130: u256 = 0x400000000000000000000000000000000; // 2^130
const TWO_POW_151: u256 = 0x80000000000000000000000000000000000000; // 2^151
const TWO_POW_172: u256 = 0x10000000000000000000000000000000000000000000; // 2^172
const TWO_POW_193: u256 = 0x2000000000000000000000000000000000000000000000000; // 2^193
const TWO_POW_214: u256 = 0x400000000000000000000000000000000000000000000000000000; // 2^214
const TWO_POW_235: u256 = 0x80000000000000000000000000000000000000000000000000000000000; // 2^235
const TWO_POW_244: u256 = 0x10000000000000000000000000000000000000000000000000000000000000; // 2^244
const TWO_POW_247: u256 = 0x80000000000000000000000000000000000000000000000000000000000000; // 2^247


// ---------------------------
// ---------- Tests ----------
Expand Down Expand Up @@ -2759,11 +2765,11 @@ mod tests {
let adventurer = Adventurer {
last_action_block: 511,
health: 511,
xp: 8191,
xp: 16383,
stats: Stats {
strength: 15,
strength: 31,
dexterity: 15,
vitality: 15,
vitality: 31,
intelligence: 15,
wisdom: 15,
charisma: 15,
Expand Down Expand Up @@ -2828,11 +2834,11 @@ mod tests {
let adventurer = Adventurer {
last_action_block: 511,
health: 511,
xp: 8191,
xp: 16383,
stats: Stats {
strength: 15,
strength: 31,
dexterity: 15,
vitality: 15,
vitality: 31,
intelligence: 15,
wisdom: 15,
charisma: 15,
Expand Down Expand Up @@ -2927,10 +2933,19 @@ mod tests {
#[available_gas(3000000)]
fn test_pack_protection_overflow_strength() {
let mut adventurer = ImplAdventurer::new(ItemId::Wand);
adventurer.stats.strength = MAX_STAT_VALUE + 1;
adventurer.stats.strength = 32;
AdventurerPacking::pack(adventurer);
}

#[test]
#[available_gas(3000000)]
fn test_pack_protection_strength() {
let mut adventurer = ImplAdventurer::new(ItemId::Wand);
adventurer.stats.strength = 31;
let unpacked: Adventurer = AdventurerPacking::unpack(AdventurerPacking::pack(adventurer));
assert(unpacked.stats.strength == adventurer.stats.strength, 'strength should be same');
}

#[test]
#[should_panic(expected: ('dexterity overflow',))]
#[available_gas(3000000)]
Expand All @@ -2945,10 +2960,19 @@ mod tests {
#[available_gas(3000000)]
fn test_pack_protection_overflow_vitality() {
let mut adventurer = ImplAdventurer::new(ItemId::Wand);
adventurer.stats.vitality = MAX_STAT_VALUE + 1;
adventurer.stats.vitality = 32;
AdventurerPacking::pack(adventurer);
}

#[test]
#[available_gas(3000000)]
fn test_pack_protection_vitality() {
let mut adventurer = ImplAdventurer::new(ItemId::Wand);
adventurer.stats.vitality = 31;
let unpacked: Adventurer = AdventurerPacking::unpack(AdventurerPacking::pack(adventurer));
assert(unpacked.stats.vitality == adventurer.stats.vitality, 'vitality should be same');
}

#[test]
#[should_panic(expected: ('intelligence overflow',))]
#[available_gas(3000000)]
Expand Down Expand Up @@ -3192,7 +3216,7 @@ mod tests {
let (previous_level, new_level) = adventurer.increase_adventurer_xp(MAX_XP + 10);
assert(adventurer.xp == MAX_XP, 'xp should stop at max xp');
assert(previous_level == 2, 'prev level should be 2');
assert(new_level == 90, 'new level should be 90');
assert(new_level == 127, 'new level should be max 127');

// u16 overflow case
adventurer.increase_adventurer_xp(65535);
Expand Down
9 changes: 6 additions & 3 deletions contracts/adventurer/src/adventurer_meta.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ impl PackingAdventurerMetadata of StorePacking<AdventurerMetadata, felt252> {

(value.start_block.into()
+ StatsPacking::pack(value.starting_stats).into() * TWO_POW_64
+ interface_camel_u256 * TWO_POW_88
+ value.name.into() * TWO_POW_89)
+ interface_camel_u256 * TWO_POW_91
+ value.name.into() * TWO_POW_92)
.try_into()
.unwrap()
}
Expand All @@ -31,7 +31,7 @@ impl PackingAdventurerMetadata of StorePacking<AdventurerMetadata, felt252> {
packed, TWO_POW_64.try_into().unwrap()
);
let (packed, starting_stats) = integer::U256DivRem::div_rem(
packed, TWO_POW_24.try_into().unwrap()
packed, TWO_POW_27.try_into().unwrap()
);
let (packed, interface_camel_u256) = integer::U256DivRem::div_rem(
packed, TWO_POW_1.try_into().unwrap()
Expand Down Expand Up @@ -68,6 +68,9 @@ const TWO_POW_64: u256 = 0x10000000000000000;
const TWO_POW_88: u256 = 0x10000000000000000000000;
const TWO_POW_89: u256 = 0x20000000000000000000000;
const TWO_POW_128: u256 = 0x100000000000000000000000000000000;
const TWO_POW_91: u256 = 0x80000000000000000000000; // 2^91
const TWO_POW_92: u256 = 0x100000000000000000000000; // 2^92
const TWO_POW_27: u256 = 0x8000000; // 2^27

#[cfg(test)]
#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
const STARTING_GOLD: u16 = 25;
const STARTING_HEALTH: u16 = 100;


// Adventurer Max Values
const MAX_ADVENTURER_HEALTH: u16 = 511; // 9 bits
const MAX_XP: u16 = 8191; // 13 bits
const MAX_XP: u16 = 16383; // 14 bits
const MAX_STAT_VALUE: u8 = 15; // 4 bits
const MAX_STAT_VALUE_5_BITS: u8 = 31; // 5 bits
const MAX_GOLD: u16 = 511; // 9 bits
const MAX_PACKABLE_ITEM_XP: u16 = 511; // 9 bits
const MAX_PACKABLE_BEAST_HEALTH: u16 = 511; // 9 bits
Expand Down
2 changes: 1 addition & 1 deletion contracts/adventurer/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ mod constants {
mod discovery_constants;
mod adventurer_constants;
}
mod leaderboard;
mod leaderboard;
32 changes: 18 additions & 14 deletions contracts/adventurer/src/stats.cairo
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use core::{option::OptionTrait, starknet::{StorePacking}, traits::{TryInto, Into}};

#[derive(Drop, Copy, Serde)]
struct Stats { // 24 storage bits
strength: u8, // 4 bits
struct Stats { // 26 storage bits
strength: u8, // 5 bits
dexterity: u8, // 4 bits
vitality: u8, // 4 bits
vitality: u8, // 5 bits
intelligence: u8, // 4 bits
wisdom: u8, // 4 bits
charisma: u8, // 4 bits
Expand All @@ -23,25 +23,25 @@ impl StatUtils of IStat {
impl StatsPacking of StorePacking<Stats, felt252> {
fn pack(value: Stats) -> felt252 {
(value.strength.into()
+ value.dexterity.into() * TWO_POW_4
+ value.vitality.into() * TWO_POW_8
+ value.intelligence.into() * TWO_POW_12
+ value.wisdom.into() * TWO_POW_16
+ value.charisma.into() * TWO_POW_20)
+ value.dexterity.into() * TWO_POW_5
+ value.vitality.into() * TWO_POW_9
+ value.intelligence.into() * TWO_POW_14
+ value.wisdom.into() * TWO_POW_18
+ value.charisma.into() * TWO_POW_22)
.try_into()
.unwrap()
}

fn unpack(value: felt252) -> Stats {
let packed = value.into();
let (packed, strength) = integer::U256DivRem::div_rem(
packed, TWO_POW_4.try_into().unwrap()
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, dexterity) = integer::U256DivRem::div_rem(
packed, TWO_POW_4.try_into().unwrap()
);
let (packed, vitality) = integer::U256DivRem::div_rem(
packed, TWO_POW_4.try_into().unwrap()
packed, TWO_POW_5.try_into().unwrap()
);
let (packed, intelligence) = integer::U256DivRem::div_rem(
packed, TWO_POW_4.try_into().unwrap()
Expand All @@ -61,11 +61,15 @@ impl StatsPacking of StorePacking<Stats, felt252> {
}
}

const TWO_POW_22: u256 = 0x400000;
const TWO_POW_9: u256 = 0x200;
const TWO_POW_10: u256 = 0x400;
const TWO_POW_5: u256 = 0x20;
const TWO_POW_4: u256 = 0x10;
const TWO_POW_8: u256 = 0x100;
const TWO_POW_12: u256 = 0x1000;
const TWO_POW_16: u256 = 0x10000;
const TWO_POW_20: u256 = 0x100000;
const TWO_POW_14: u256 = 0x4000;
const TWO_POW_18: u256 = 0x40000;
const TWO_POW_24: u256 = 0x1000000;

// ---------------------------
Expand Down Expand Up @@ -95,9 +99,9 @@ mod tests {

// storage limit test (2^4 - 1 = 15)
let stats = Stats {
strength: 15,
strength: 31,
dexterity: 15,
vitality: 15,
vitality: 31,
intelligence: 15,
wisdom: 15,
charisma: 15,
Expand Down
Loading
Loading