Proper character HP in battle, fix some ordering issues
This commit is contained in:
parent
eb641d67fb
commit
0e0a78abaa
15 changed files with 234 additions and 64 deletions
|
@ -41,6 +41,8 @@ tracing-subscriber = { version = "0.3.18", features = [
|
|||
] }
|
||||
tracing-bunyan-formatter = "0.3.9"
|
||||
|
||||
itertools = "0.13.0"
|
||||
|
||||
common = { version = "0.1.0", path = "common" }
|
||||
protocol = { version = "0.1.0", path = "protocol" }
|
||||
qwer = { version = "0.1.0", path = "qwer", features = ["full"] }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub fn load_or_create_config(path: &str, defaults: &str) -> String {
|
||||
std::fs::read_to_string(path).map_or_else(
|
||||
|_| {
|
||||
|
@ -7,3 +9,17 @@ pub fn load_or_create_config(path: &str, defaults: &str) -> String {
|
|||
|data| data,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn cur_timestamp_ms() -> i64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis() as i64
|
||||
}
|
||||
|
||||
pub fn cur_timestamp_seconds() -> i64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs() as i64
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ hex.workspace = true
|
|||
lazy_static.workspace = true
|
||||
paste.workspace = true
|
||||
sysinfo.workspace = true
|
||||
itertools.workspace = true
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
|
|
@ -92,21 +92,25 @@ impl DungeonManager {
|
|||
},
|
||||
};
|
||||
|
||||
let add_dungeon = dungeon_info.clone();
|
||||
let add_scene = scene_info.clone();
|
||||
let cur_scene_uid = scene_info.get_uid();
|
||||
|
||||
Ok(PlayerOperationResult::with_changes(
|
||||
ptc_enter_scene,
|
||||
PlayerInfo {
|
||||
dungeon_collection: Some(DungeonCollection {
|
||||
dungeons: Some(PropertyHashMap::Modify {
|
||||
to_add: vec![(dungeon_info.uid, dungeon_info.clone())],
|
||||
to_add: vec![(add_dungeon.uid, add_dungeon)],
|
||||
to_remove: Vec::new(),
|
||||
}),
|
||||
scenes: Some(PropertyHashMap::Modify {
|
||||
to_add: vec![(scene_info.get_uid(), scene_info.clone())],
|
||||
to_add: vec![(add_scene.get_uid(), add_scene)],
|
||||
to_remove: Vec::new(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
scene_uid: Some(scene_info.get_uid()),
|
||||
scene_uid: Some(cur_scene_uid),
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
|
@ -259,6 +263,8 @@ impl DungeonManager {
|
|||
.get_mut(&cur_scene_uid)
|
||||
.unwrap();
|
||||
|
||||
let dungeon_uid = hollow_scene.get_dungeon_uid();
|
||||
|
||||
if let SceneInfo::Hollow {
|
||||
hollow_system_ui_state,
|
||||
..
|
||||
|
@ -271,12 +277,33 @@ impl DungeonManager {
|
|||
hollow_system_ui_state.insert(HollowSystemType::Menu, HollowSystemUIState::Close);
|
||||
}
|
||||
|
||||
let add_scene = hollow_scene.clone();
|
||||
|
||||
let quest_data = player.quest_data.as_ref().unwrap();
|
||||
let mut dungeon_quest = quest_data
|
||||
.quests
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&dungeon_uid, &1001000101)
|
||||
.unwrap()
|
||||
.clone();
|
||||
dungeon_quest.set_progress(1);
|
||||
dungeon_quest.set_finished_count(1);
|
||||
dungeon_quest.set_state(QuestState::Finished);
|
||||
|
||||
PlayerOperationResult::with_changes(
|
||||
cur_scene_uid,
|
||||
PlayerInfo {
|
||||
dungeon_collection: Some(DungeonCollection {
|
||||
scenes: Some(PropertyHashMap::Modify {
|
||||
to_add: vec![(cur_scene_uid, hollow_scene.clone())],
|
||||
to_add: vec![(cur_scene_uid, add_scene)],
|
||||
to_remove: Vec::new(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
quest_data: Some(QuestData {
|
||||
quests: Some(PropertyDoubleKeyHashMap::Modify {
|
||||
to_add: vec![(dungeon_uid, 1001000101, dungeon_quest)],
|
||||
to_remove: Vec::new(),
|
||||
}),
|
||||
..Default::default()
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
const BASE_UID: u64 = 1000000;
|
||||
|
||||
pub struct UniqueIDManager {
|
||||
uid_counter: AtomicU64,
|
||||
}
|
||||
pub struct UniqueIDManager(AtomicU64);
|
||||
|
||||
impl UniqueIDManager {
|
||||
const BASE_UID: u64 = 1000000;
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
uid_counter: AtomicU64::new(BASE_UID),
|
||||
}
|
||||
Self(AtomicU64::new(Self::BASE_UID))
|
||||
}
|
||||
|
||||
pub fn next(&self) -> u64 {
|
||||
let uid = self.uid_counter.load(Ordering::SeqCst) + 1;
|
||||
self.uid_counter.store(uid, Ordering::SeqCst);
|
||||
|
||||
uid
|
||||
self.0.fetch_add(1, Ordering::SeqCst) + 1
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ pub async fn listen(bind_addr: &str) -> Result<()> {
|
|||
|
||||
tracing::info!("New session from {client_addr}");
|
||||
|
||||
let mut session = NetworkSession::new(client_socket, client_addr);
|
||||
let mut session = NetworkSession::new(client_socket);
|
||||
tokio::spawn(
|
||||
async move {
|
||||
log_error!(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use common::util;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -28,15 +28,11 @@ pub async fn on_rpc_beginnerbattle_begin_arg(
|
|||
session: &NetworkSession,
|
||||
arg: &RpcBeginnerbattleBeginArg,
|
||||
) -> Result<()> {
|
||||
let cur_timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
session
|
||||
.send_rpc_ret(RpcBeginnerbattleBeginRet::new(format!(
|
||||
"{cur_timestamp}-{}",
|
||||
arg.battle_id
|
||||
"{}-{}",
|
||||
arg.battle_id,
|
||||
util::cur_timestamp_seconds()
|
||||
)))
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use itertools::Itertools;
|
||||
use qwer::{phashmap, phashset, PropertyHashMap, PropertyHashSet};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::data;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_rpc_hollow_move_arg(
|
||||
|
@ -59,7 +62,7 @@ pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleA
|
|||
quest_id: 1001000101,
|
||||
success: true,
|
||||
reward_items: phashmap![],
|
||||
statistics: phashmap![],
|
||||
statistics: phashmap![(QuestStatisticsType::ArrivedLevel, 1)],
|
||||
};
|
||||
|
||||
session
|
||||
|
@ -211,12 +214,31 @@ pub async fn on_rpc_start_hollow_quest_arg(
|
|||
) -> Result<()> {
|
||||
tracing::info!("start hollow quest: {arg:?}");
|
||||
|
||||
// Set avatar HP properties
|
||||
for (_idx, avatar_uid) in &arg.avatar_map {
|
||||
// Set character HP
|
||||
let player_info = session.get_player();
|
||||
let items = player_info.items.as_ref().unwrap();
|
||||
let Some(ItemInfo::Avatar { id, .. }) = items
|
||||
.iter()
|
||||
.find(|(uid, _)| **uid == *avatar_uid)
|
||||
.map(|(_, item)| item)
|
||||
else {
|
||||
return session
|
||||
.send_rpc_ret(RpcStartHollowQuestRet::error(
|
||||
ErrorCode::ObjectNotExist,
|
||||
Vec::new(),
|
||||
))
|
||||
.await;
|
||||
};
|
||||
|
||||
let avatar_config = data::iter_avatar_config_collection()
|
||||
.find(|c| c.id == *id)
|
||||
.unwrap();
|
||||
|
||||
let update_properties = PtcPropertyChangedArg {
|
||||
scene_unit_uid: *avatar_uid,
|
||||
is_partial: true,
|
||||
changed_properties: phashmap![(1, 500), (111, 500)],
|
||||
changed_properties: phashmap![(1, avatar_config.hp), (111, avatar_config.hp)],
|
||||
};
|
||||
|
||||
session.send_rpc_arg(129, &update_properties).await?;
|
||||
|
@ -227,6 +249,7 @@ pub async fn on_rpc_start_hollow_quest_arg(
|
|||
let avatars = arg
|
||||
.avatar_map
|
||||
.iter()
|
||||
.sorted_by_key(|kv| kv.0)
|
||||
.map(|(_idx, uid)| *uid)
|
||||
.collect::<Vec<_>>();
|
||||
let (dungeon_uid, scene_uid) = *dungeon_manager
|
||||
|
|
|
@ -227,7 +227,7 @@ pub async fn on_rpc_enter_world_arg(
|
|||
|
||||
let quest_manager = session.context.quest_manager.borrow();
|
||||
quest_manager.add_world_quest(QuestInfo::MainCity {
|
||||
id: 10020001,
|
||||
id: 10020002,
|
||||
finished_count: 0,
|
||||
collection_uid: 0,
|
||||
progress: 0,
|
||||
|
|
|
@ -3,7 +3,6 @@ use atomic_refcell::{AtomicRef, AtomicRefMut};
|
|||
use protocol::*;
|
||||
use qwer::{OctData, ProtocolHeader};
|
||||
use std::io::Cursor;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
|
@ -16,25 +15,27 @@ use super::{packet::PacketHandler, Packet, RequestBody, ResponseBody};
|
|||
|
||||
pub struct NetworkSession {
|
||||
client_socket: Arc<Mutex<TcpStream>>,
|
||||
client_addr: SocketAddr,
|
||||
cur_rpc_uid: u64,
|
||||
pub ns_prop_mgr: net_stream::PropertyManager,
|
||||
pub context: GameContext,
|
||||
}
|
||||
|
||||
impl NetworkSession {
|
||||
pub fn new(client_socket: TcpStream, client_addr: SocketAddr) -> Self {
|
||||
pub fn new(client_socket: TcpStream) -> Self {
|
||||
let ns_prop_mgr = net_stream::PropertyManager::default();
|
||||
|
||||
Self {
|
||||
client_socket: Arc::new(Mutex::new(client_socket)),
|
||||
client_addr,
|
||||
cur_rpc_uid: 0,
|
||||
context: GameContext::new(ns_prop_mgr.player_info.clone()),
|
||||
ns_prop_mgr,
|
||||
}
|
||||
}
|
||||
|
||||
async fn client_socket(&self) -> MutexGuard<'_, TcpStream> {
|
||||
self.client_socket.lock().await
|
||||
}
|
||||
|
||||
pub fn get_player_uid(&self) -> u64 {
|
||||
self.get_player().uid.unwrap()
|
||||
}
|
||||
|
@ -55,20 +56,10 @@ impl NetworkSession {
|
|||
self.ns_prop_mgr.player_info.try_borrow_mut().unwrap()
|
||||
}
|
||||
|
||||
pub async fn client_socket(&self) -> MutexGuard<'_, TcpStream> {
|
||||
self.client_socket.lock().await
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<()> {
|
||||
let channel_id = match self.read_handshake().await {
|
||||
Ok(channel_id) => channel_id,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(()),
|
||||
Err(e) => return Err(e.into()),
|
||||
let Some(_channel_id) = self.read_handshake().await? else {
|
||||
return Ok(());
|
||||
};
|
||||
tracing::info!(
|
||||
"Session ({}) bound to channel {channel_id}",
|
||||
self.client_addr
|
||||
);
|
||||
|
||||
loop {
|
||||
let packet = match Packet::read(&mut *self.client_socket().await).await {
|
||||
|
@ -83,8 +74,12 @@ impl NetworkSession {
|
|||
}
|
||||
}
|
||||
|
||||
async fn read_handshake(&mut self) -> Result<u16, std::io::Error> {
|
||||
self.client_socket().await.read_u16_le().await
|
||||
async fn read_handshake(&mut self) -> Result<Option<u16>> {
|
||||
match self.client_socket().await.read_u16_le().await {
|
||||
Ok(channel_id) => Ok(Some(channel_id)),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Ok(None),
|
||||
Err(e) => return Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_rpc_ret(&self, data: impl OctData) -> Result<()> {
|
||||
|
|
|
@ -5,9 +5,101 @@ use super::*;
|
|||
pub enum ErrorCode {
|
||||
Fail = -1,
|
||||
Success = 0,
|
||||
Timeout = 1,
|
||||
EntityNotExist = 2,
|
||||
InvalidVersion = 3,
|
||||
InvalidTemplateID = 4,
|
||||
InvalidConfigVersion = 5,
|
||||
ObjectNotExist = 100,
|
||||
ConfigError = 101,
|
||||
NoEnoughRes = 102,
|
||||
NoEnoughEXP = 103,
|
||||
NoEnoughItem = 104,
|
||||
NoEnoughMaterials = 105,
|
||||
NoEnoughGoods = 106,
|
||||
NoEnoughCurrency = 107,
|
||||
CannotFindGoods = 108,
|
||||
AvatarMaxLevelLimit = 109,
|
||||
AvatarMaxStarLimit = 110,
|
||||
AvatarMaxAdvanceLevelLimit = 111,
|
||||
EquipMaxLevelLimit = 112,
|
||||
EquipMaxStarLimit = 113,
|
||||
SceneAlreadyDestroyed = 114,
|
||||
StageAlreadyDestroyed = 115,
|
||||
ErrorSrcPosition = 116,
|
||||
ErrorGraph = 117,
|
||||
NodeFinished = 118,
|
||||
NodeRunFailure = 119,
|
||||
UnknownAvatarSkill = 120,
|
||||
AvatarSkillMaxLevelLimit = 121,
|
||||
AvatarTalentMaxLevelLimit = 122,
|
||||
AvatarStarNotEnough = 123,
|
||||
InvalidActionMovePath = 124,
|
||||
ActionIDNotExist = 125,
|
||||
NickNameMaxLength = 126,
|
||||
NickNameIllegal = 127,
|
||||
Ban = 128,
|
||||
RepeatedLogin = 129,
|
||||
FuncNotOpen = 130,
|
||||
TokenError = 131,
|
||||
PlayerNotExist = 132,
|
||||
InvalidParam = 133,
|
||||
ItemBeOccupy = 134,
|
||||
ItemBeLock = 135,
|
||||
EquipGachaClose = 136,
|
||||
InvalidQuestState = 137,
|
||||
QuestMaxFinishCnt = 138,
|
||||
NoEnoughTimes = 139,
|
||||
BattleReportLimit = 140,
|
||||
BattleReportInvalid = 141,
|
||||
MaxLevelLimit = 142,
|
||||
MaxStarLimit = 143,
|
||||
MaxRefineLimit = 144,
|
||||
AlreadyGet = 145,
|
||||
RepeatedModName = 146,
|
||||
VHSStoreUnlock = 147,
|
||||
VHSStoreAlreadSlot = 148,
|
||||
VHSStoreSlotNumErr = 149,
|
||||
FuncNotUnlock = 150,
|
||||
VHSStoreRamenContinueEat = 151,
|
||||
VHSStoreAlreadyUnlock = 152,
|
||||
AFKGamePlayClose = 153,
|
||||
InitiativeItemUnlock = 154,
|
||||
InitiativeItemLevel = 155,
|
||||
PrepareAvatarsFail = 156,
|
||||
AlreadyAFK = 157,
|
||||
HollowDoEvtListNotEmpty = 158,
|
||||
HollowEvtNotCompleted = 159,
|
||||
HollowMoveFail = 160,
|
||||
BuyNumOverflow = 161,
|
||||
PackgeOverflow = 162,
|
||||
ReplacePkg = 163,
|
||||
FileLenghCheckFaild = 164,
|
||||
HashCheckFaild = 165,
|
||||
DiskNotEnough = 166,
|
||||
NotReachable = 167,
|
||||
ServerException = 168,
|
||||
RequestException = 169,
|
||||
OherDownLoadError = 170,
|
||||
QuestProgressNotEnough = 171,
|
||||
ConditionComplete = 172,
|
||||
ConditionNoComplete = 173,
|
||||
PayErrCode0 = 174,
|
||||
PayErrCode1 = 175,
|
||||
PayErrCode2 = 176,
|
||||
PayErrCode3 = 177,
|
||||
PayErrCode4 = 178,
|
||||
PayErrCode5 = 179,
|
||||
NoWhite = 180,
|
||||
NoWhiteDevice = 181,
|
||||
NoWhiteIp = 182,
|
||||
SdkError = 183,
|
||||
StopServer = 184,
|
||||
AccountServerError = 185,
|
||||
CloseServer = 187,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum HollowQuestType {
|
||||
Common = 0,
|
||||
|
@ -48,7 +140,7 @@ pub enum FightRanking {
|
|||
S = 5,
|
||||
}
|
||||
|
||||
#[derive(OctData, Hash, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(OctData, Hash, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
#[repr(i16)]
|
||||
pub enum BattleRewardType {
|
||||
Client = 1,
|
||||
|
@ -79,7 +171,7 @@ pub enum HollowBattleEventType {
|
|||
LevelFin = 5,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum QuestType {
|
||||
ArchiveFile = 1,
|
||||
|
@ -113,7 +205,7 @@ pub enum ActionState {
|
|||
Error = 3,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum DungeonContentDropPoolType {
|
||||
Card = 0,
|
||||
|
@ -143,14 +235,14 @@ pub enum UIType {
|
|||
Archive = 3,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum ACTPerformShowMoment {
|
||||
Begin = 0,
|
||||
End = 1,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum HollowSystemType {
|
||||
Card = 1,
|
||||
|
@ -170,7 +262,7 @@ pub enum HollowSystemUIState {
|
|||
Brighten = 2,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum HollowShopType {
|
||||
All = 0,
|
||||
|
@ -203,7 +295,7 @@ pub enum WeatherType {
|
|||
Thunder = 5,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum PropertyType {
|
||||
Hp = 1,
|
||||
|
@ -333,7 +425,7 @@ pub enum PropertyType {
|
|||
EnumCount = 10351,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(i16)]
|
||||
pub enum ScenePropertyType {
|
||||
Stamina = 1001,
|
||||
|
@ -535,7 +627,7 @@ pub enum QuestState {
|
|||
Finished = 3,
|
||||
}
|
||||
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(OctData, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum QuestStatisticsType {
|
||||
ArrivedLevel = 1,
|
||||
|
|
|
@ -658,6 +658,30 @@ macro_rules! polymorphic_quest_info {
|
|||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_state(&mut self, state: QuestState) {
|
||||
match self {
|
||||
$(
|
||||
$name::$variant { state: ref mut c, .. } => *c = state,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_progress(&mut self, progress: u16) {
|
||||
match self {
|
||||
$(
|
||||
$name::$variant { progress: ref mut c, .. } => *c = progress,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_finished_count(&mut self, finished_count: i32) {
|
||||
match self {
|
||||
$(
|
||||
$name::$variant { finished_count: ref mut c, .. } => *c = finished_count,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,3 +13,4 @@ protocol = []
|
|||
[dependencies]
|
||||
byteorder.workspace = true
|
||||
qwer-derive.workspace = true
|
||||
itertools.workspace = true
|
||||
|
|
|
@ -612,7 +612,7 @@ fn test_dkhashmap_iter() {
|
|||
|
||||
impl<K, V> OctData for PropertyHashMap<K, V>
|
||||
where
|
||||
K: OctData + Eq + std::hash::Hash,
|
||||
K: OctData + Eq + Ord + std::hash::Hash,
|
||||
V: OctData,
|
||||
{
|
||||
fn marshal_to<W: std::io::Write>(&self, w: &mut W, bt_property_tag: u16) -> Result<()> {
|
||||
|
@ -721,8 +721,8 @@ where
|
|||
|
||||
impl<K1, K2, V> OctData for PropertyDoubleKeyHashMap<K1, K2, V>
|
||||
where
|
||||
K1: OctData + Eq + std::hash::Hash,
|
||||
K2: OctData + Eq + std::hash::Hash,
|
||||
K1: OctData + Eq + Ord + std::hash::Hash,
|
||||
K2: OctData + Eq + Ord + std::hash::Hash,
|
||||
V: OctData,
|
||||
{
|
||||
fn marshal_to<W: std::io::Write>(&self, w: &mut W, bt_property_tag: u16) -> Result<()> {
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
|||
};
|
||||
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use itertools::Itertools;
|
||||
|
||||
pub use qwer_derive::OctData;
|
||||
|
||||
|
@ -133,12 +134,12 @@ where
|
|||
|
||||
impl<K, V> OctData for HashMap<K, V>
|
||||
where
|
||||
K: OctData + Eq + Hash,
|
||||
K: OctData + Eq + Hash + Ord,
|
||||
V: OctData,
|
||||
{
|
||||
default fn marshal_to<W: Write>(&self, w: &mut W, bt_property_tag: u16) -> Result<()> {
|
||||
(self.len() as i32).marshal_to(w, bt_property_tag)?;
|
||||
for (key, value) in self {
|
||||
for (key, value) in self.iter().sorted_by_key(|kv| kv.0) {
|
||||
key.marshal_to(w, bt_property_tag)?;
|
||||
value.marshal_to(w, bt_property_tag)?;
|
||||
}
|
||||
|
@ -164,8 +165,8 @@ where
|
|||
#[cfg(feature = "collection")]
|
||||
impl<K1, K2, V> OctData for DoubleKeyHashMap<K1, K2, V>
|
||||
where
|
||||
K1: OctData + Eq + Hash,
|
||||
K2: OctData + Eq + Hash,
|
||||
K1: OctData + Eq + Hash + Ord,
|
||||
K2: OctData + Eq + Hash + Ord,
|
||||
V: OctData,
|
||||
{
|
||||
fn marshal_to<W: Write>(&self, w: &mut W, bt_property_tag: u16) -> Result<()> {
|
||||
|
|
Loading…
Reference in a new issue