rust/lib-hedgewars-engine/src/time.rs
author S.D.
Tue, 27 Sep 2022 14:59:03 +0300
changeset 15900 fc3cb23fd26f
parent 15850 44b49f255e31
permissions -rw-r--r--
Allow to see rooms of incompatible versions in the lobby For the new clients the room version is shown in a separate column. There is also a hack for previous versions clients: the room vesion specifier is prepended to the room names for rooms of incompatible versions, and the server shows 'incompatible version' error if the client tries to join them.

use hwphysics::common::{GearId, Millis};
use std::{
    cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
    collections::BinaryHeap,
};

pub type EventId = u16;

struct TimeEvent {
    time: Millis,
    gear_id: GearId,
    event_id: EventId,
}

impl PartialOrd for TimeEvent {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl PartialEq for TimeEvent {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.time.eq(&other.time)
    }
}

impl Ord for TimeEvent {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.time.cmp(&other.time)
    }
}

impl Eq for TimeEvent {}

pub struct OccurredEvents {
    events: Vec<(GearId, EventId)>,
}

impl OccurredEvents {
    fn new() -> Self {
        Self { events: vec![] }
    }

    fn clear(&mut self) {
        self.events.clear()
    }
}

pub struct TimeProcessor {
    current_event_id: EventId,
    current_time: Millis,
    events: BinaryHeap<TimeEvent>,
    timeouts: OccurredEvents,
}

impl TimeProcessor {
    pub fn new() -> Self {
        Self {
            current_event_id: 0,
            current_time: Millis::new(0),
            events: BinaryHeap::with_capacity(1024),
            timeouts: OccurredEvents::new(),
        }
    }

    pub fn register(&mut self, gear_id: GearId, timeout: Millis) -> EventId {
        let event_id = self.current_event_id;
        self.current_event_id = self.current_event_id.wrapping_add(1);
        let event = TimeEvent {
            time: self.current_time + timeout,
            gear_id,
            event_id,
        };
        self.events.push(event);
        event_id
    }

    fn retain_events<P>(&mut self, predicate: P)
    where
        P: Fn(&TimeEvent) -> bool,
    {
        let events = self.events.drain().filter(predicate).collect::<Vec<_>>();
        self.events.extend(events);
    }

    pub fn cancel(&mut self, event_id: EventId) {
        //self.events.retain(|event| event.event_id != event_id)
        self.retain_events(|event| event.event_id != event_id)
    }

    pub fn cancel_all(&mut self, gear_id: GearId) {
        //self.events.retain(|event| event.gear_id != gear_id)
        self.retain_events(|event| event.gear_id != gear_id)
    }

    pub fn process(&mut self, time_step: Millis) -> &OccurredEvents {
        self.timeouts.clear();
        self.current_time = self.current_time + time_step;
        while self
            .events
            .peek()
            .filter(|e| e.time <= self.current_time)
            .is_some()
        {
            let event = self.events.pop().unwrap();
            self.timeouts.events.push((event.gear_id, event.event_id))
        }
        &self.timeouts
    }
}