mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add game event refresh freezing when user enters lobby; fix #84
This commit is contained in:
@@ -79,6 +79,21 @@ impl GameMap {
|
||||
crate::persist::config::GameMap::Earth2 => Self::Earth2,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"RC_Planet_Mars_01_CTF" => Some(Self::Mars1), // og flat mars
|
||||
"RC_Planet_Mars_02_BA" => Some(Self::Mars2), // the one with the bridge in the middle
|
||||
"RC_Planet_Mars_03_BA" => Some(Self::Mars3), // tharsis rift without the rift
|
||||
"RC_Planet_Neptune_01_CTF" => Some(Self::Neptune1), // og flat GJ1214b gliese lake without the lake
|
||||
"RC_Planet_Neptune_02_BA" => Some(Self::Neptune2), // the one with the cave
|
||||
"RC_Planet_Neptune_03_BA" => Some(Self::Neptune3), // spitzer dam
|
||||
"RC_Planet_Earth_01_BA" => Some(Self::Earth1), // birmingham power station
|
||||
"RC_Planet_Earth_02_BA" => Some(Self::Earth2), // vanguard
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
|
||||
@@ -379,6 +379,7 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
||||
index: first,
|
||||
started: chrono::Utc::now().timestamp(),
|
||||
needs_to_be_saved: true,
|
||||
lockouts: std::collections::HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,17 +164,18 @@ pub struct ChatSystemConfig {
|
||||
pub can_create_channels: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct GameEventSequence {
|
||||
pub strategy: GameRotationStrategy,
|
||||
pub modes: Vec<GameEvents>,
|
||||
pub index: usize,
|
||||
pub started: i64,
|
||||
pub(crate) needs_to_be_saved: bool,
|
||||
pub(crate) lockouts: std::collections::HashMap<i32, GameEvent>,
|
||||
}
|
||||
|
||||
impl GameEventSequence {
|
||||
pub fn now(&mut self, updater: Box<dyn crate::persist::user::GameEventSetter>) -> GameEventTransmissible {
|
||||
pub fn now(&mut self, updater: Box<dyn crate::persist::user::GameEventSetter>, user: i32) -> GameEventTransmissible {
|
||||
let time_now = chrono::Utc::now().timestamp();
|
||||
let mut item_now = &self.modes[self.index];
|
||||
let needs_refresh = time_now >= (item_now.duration.as_secs() as i64) + self.started;
|
||||
@@ -207,43 +208,91 @@ impl GameEventSequence {
|
||||
updater.set_singleplayer(sp).await;
|
||||
});
|
||||
}
|
||||
let remaining_ticks = ((item_now.duration.as_secs() as i64) - (time_now - self.started)) * 10_000_000;
|
||||
GameEventTransmissible {
|
||||
maps: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Str,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(item_now.singleplayer.map).as_str().into()),
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(item_now.multiplayer.map).as_str().into()),
|
||||
],
|
||||
}),
|
||||
visibilities: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(item_now.singleplayer.visibility) as _),
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(item_now.multiplayer.visibility) as _),
|
||||
],
|
||||
}),
|
||||
modes: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(item_now.singleplayer.mode) as _),
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(item_now.multiplayer.mode) as _),
|
||||
],
|
||||
}),
|
||||
auto_heals: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Bool,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Bool(item_now.singleplayer.auto_heal),
|
||||
Typed::Bool(item_now.multiplayer.auto_heal),
|
||||
],
|
||||
}),
|
||||
remaining_ticks: Typed::Long(remaining_ticks),
|
||||
if let Some(multiplayer_override) = self.lockouts.get(&user) {
|
||||
GameEventTransmissible {
|
||||
maps: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Str,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(item_now.singleplayer.map).as_str().into()),
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(multiplayer_override.map).as_str().into()),
|
||||
],
|
||||
}),
|
||||
visibilities: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(item_now.singleplayer.visibility) as _),
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(multiplayer_override.visibility) as _),
|
||||
],
|
||||
}),
|
||||
modes: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(item_now.singleplayer.mode) as _),
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(multiplayer_override.mode) as _),
|
||||
],
|
||||
}),
|
||||
auto_heals: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Bool,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Bool(item_now.singleplayer.auto_heal),
|
||||
Typed::Bool(multiplayer_override.auto_heal),
|
||||
],
|
||||
}),
|
||||
remaining_ticks: Typed::Long(10_000_000),
|
||||
}
|
||||
} else {
|
||||
let remaining_ticks = ((item_now.duration.as_secs() as i64) - (time_now - self.started)) * 10_000_000;
|
||||
GameEventTransmissible {
|
||||
maps: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Str,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(item_now.singleplayer.map).as_str().into()),
|
||||
Typed::Str(crate::data::game_mode::GameMap::from_persist(item_now.multiplayer.map).as_str().into()),
|
||||
],
|
||||
}),
|
||||
visibilities: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(item_now.singleplayer.visibility) as _),
|
||||
Typed::Int(crate::data::game_mode::MapVisibility::from_persist(item_now.multiplayer.visibility) as _),
|
||||
],
|
||||
}),
|
||||
modes: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Int,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(item_now.singleplayer.mode) as _),
|
||||
Typed::Int(crate::data::game_mode::GameMode::from_persist(item_now.multiplayer.mode) as _),
|
||||
],
|
||||
}),
|
||||
auto_heals: Typed::Arr(polariton::operation::Arr {
|
||||
ty: polariton::serdes::TypePrefix::Bool,
|
||||
custom_ty: None,
|
||||
items: vec![
|
||||
Typed::Bool(item_now.singleplayer.auto_heal),
|
||||
Typed::Bool(item_now.multiplayer.auto_heal),
|
||||
],
|
||||
}),
|
||||
remaining_ticks: Typed::Long(remaining_ticks),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if replacing existing entry for user
|
||||
pub fn add_lockout(&mut self, user: i32, event: GameEvent) -> bool {
|
||||
self.lockouts.insert(user, event).is_some()
|
||||
}
|
||||
|
||||
/// Returns true if entry for user existed
|
||||
pub fn remove_lockout(&mut self, user: i32) -> bool {
|
||||
self.lockouts.remove(&user).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GameEventTransmissible {
|
||||
|
||||
@@ -229,14 +229,20 @@ impl super::IntercomUser for super::account_json::UserData {
|
||||
|
||||
async fn trigger_workaround(&self, msg: IntercomWorkaroundMessage, to: Vec<String>) {
|
||||
let send_to_everyone = to.is_empty();
|
||||
let data = IntercomWebServiceMessage {
|
||||
public_ids: to,
|
||||
data: IntercomWebServiceUserMessage::Workaround(msg),
|
||||
everyone: send_to_everyone,
|
||||
};
|
||||
if let Err(e) = self.post_to_intercom(&data, ".oj_services", "messages").await {
|
||||
log::error!("Failed to send intercom workaround message: {}", e);
|
||||
match msg {
|
||||
IntercomWorkaroundMessage::Lobby(_lobby) => todo!(),
|
||||
IntercomWorkaroundMessage::WebService(ws) => {
|
||||
let data = IntercomWebServiceMessage {
|
||||
public_ids: to,
|
||||
data: IntercomWebServiceUserMessage::Workaround(ws),
|
||||
everyone: send_to_everyone,
|
||||
};
|
||||
if let Err(e) = self.post_to_intercom(&data, ".oj_services", "messages").await {
|
||||
log::error!("Failed to send intercom workaround message: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fn update_custom_game(&self, msg: IntercomLobbyCustomGameDataMessage) {
|
||||
@@ -266,26 +272,127 @@ pub struct IntercomLobbyCustomGameDataMessage {
|
||||
pub users: Vec<IntercomLobbyCustomGameUserData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum CustomGameMode {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
||||
pub enum IntercomGameMap {
|
||||
Mars1,
|
||||
Mars2,
|
||||
Mars3,
|
||||
Neptune1,
|
||||
Neptune2,
|
||||
Neptune3,
|
||||
Earth1,
|
||||
Earth2,
|
||||
}
|
||||
|
||||
impl IntercomGameMap {
|
||||
pub fn into_conf(self) -> crate::persist::config::GameMap {
|
||||
match self {
|
||||
Self::Mars1 => crate::persist::config::GameMap::Mars1,
|
||||
Self::Mars2 => crate::persist::config::GameMap::Mars2,
|
||||
Self::Mars3 => crate::persist::config::GameMap::Mars3,
|
||||
Self::Neptune1 => crate::persist::config::GameMap::Neptune1,
|
||||
Self::Neptune2 => crate::persist::config::GameMap::Neptune2,
|
||||
Self::Neptune3 => crate::persist::config::GameMap::Neptune3,
|
||||
Self::Earth1 => crate::persist::config::GameMap::Earth1,
|
||||
Self::Earth2 => crate::persist::config::GameMap::Earth2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(map: crate::data::game_mode::GameMap) -> Self {
|
||||
match map {
|
||||
crate::data::game_mode::GameMap::Mars1 => Self::Mars1,
|
||||
crate::data::game_mode::GameMap::Mars2 => Self::Mars2,
|
||||
crate::data::game_mode::GameMap::Mars3 => Self::Mars3,
|
||||
crate::data::game_mode::GameMap::Neptune1 => Self::Neptune1,
|
||||
crate::data::game_mode::GameMap::Neptune2 => Self::Neptune2,
|
||||
crate::data::game_mode::GameMap::Neptune3 => Self::Neptune3,
|
||||
crate::data::game_mode::GameMap::Earth1 => Self::Earth1,
|
||||
crate::data::game_mode::GameMap::Earth2 => Self::Earth2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
"RC_Planet_Mars_01_CTF" => Some(Self::Mars1),
|
||||
"RC_Planet_Mars_02_BA" => Some(Self::Mars2),
|
||||
"RC_Planet_Mars_03_BA" => Some(Self::Mars3),
|
||||
"RC_Planet_Neptune_01_CTF" => Some(Self::Neptune1),
|
||||
"RC_Planet_Neptune_02_BA" => Some(Self::Neptune2),
|
||||
"RC_Planet_Neptune_03_BA" => Some(Self::Neptune3),
|
||||
"RC_Planet_Earth_01_BA" => Some(Self::Earth1),
|
||||
"RC_Planet_Earth_02_BA" => Some(Self::Earth2),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
||||
pub enum IntercomGameMode {
|
||||
BattleArena,
|
||||
TeamDeathmatch,
|
||||
Pit,
|
||||
SuddenDeath,
|
||||
}
|
||||
|
||||
impl IntercomGameMode {
|
||||
pub fn into_conf(self) -> crate::persist::config::GameType {
|
||||
match self {
|
||||
Self::BattleArena => crate::persist::config::GameType::BattleArena,
|
||||
Self::SuddenDeath => crate::persist::config::GameType::SuddenDeath,
|
||||
Self::Pit => crate::persist::config::GameType::Pit,
|
||||
Self::TeamDeathmatch => crate::persist::config::GameType::TeamDeathmatch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(mode: crate::data::game_mode::GameMode) -> Self {
|
||||
match mode {
|
||||
crate::data::game_mode::GameMode::BattleArena => Self::BattleArena,
|
||||
crate::data::game_mode::GameMode::SuddenDeath => Self::SuddenDeath,
|
||||
crate::data::game_mode::GameMode::Pit => Self::Pit,
|
||||
crate::data::game_mode::GameMode::TeamDeathmatch => Self::TeamDeathmatch,
|
||||
_ => Self::Pit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
||||
pub enum CustomGameVisibility {
|
||||
pub enum IntercomGameVisibility {
|
||||
Good,
|
||||
Poor,
|
||||
Bad,
|
||||
}
|
||||
|
||||
impl IntercomGameVisibility {
|
||||
pub fn into_conf(self) -> crate::persist::config::GameVisibility {
|
||||
match self {
|
||||
Self::Good => crate::persist::config::GameVisibility::Good,
|
||||
Self::Poor => crate::persist::config::GameVisibility::Poor,
|
||||
Self::Bad => crate::persist::config::GameVisibility::Bad,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(vis: crate::data::game_mode::MapVisibility) -> Self {
|
||||
match vis {
|
||||
crate::data::game_mode::MapVisibility::Good => Self::Good,
|
||||
crate::data::game_mode::MapVisibility::Poor => Self::Poor,
|
||||
crate::data::game_mode::MapVisibility::Bad => Self::Bad,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
||||
pub struct IntercomGameEvent {
|
||||
pub map: IntercomGameMap,
|
||||
pub visibility: IntercomGameVisibility,
|
||||
pub mode: IntercomGameMode,
|
||||
pub auto_heal: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct IntercomLobbyCustomGameConfig {
|
||||
pub game_mode: CustomGameMode,
|
||||
pub game_mode: IntercomGameMode,
|
||||
pub map: String,
|
||||
pub map_visibility: CustomGameVisibility,
|
||||
pub map_visibility: IntercomGameVisibility,
|
||||
pub health_regen: bool,
|
||||
pub capture_segment_memory: bool,
|
||||
pub base_shields_go_down: bool,
|
||||
@@ -350,7 +457,7 @@ pub struct IntercomWebServiceMessage {
|
||||
pub enum IntercomWebServiceUserMessage {
|
||||
DevMessage(IntercomDevMessage),
|
||||
Maintenance(IntercomMaintenanceMessage),
|
||||
Workaround(IntercomWorkaroundMessage),
|
||||
Workaround(IntercomWebServiceWorkaroundMessage),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
@@ -366,10 +473,31 @@ pub struct IntercomMaintenanceMessage {
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "workaround")]
|
||||
pub enum IntercomWorkaroundMessage {
|
||||
pub enum IntercomWebServiceWorkaroundMessage {
|
||||
/// Trigger fix for getting stuck in build mode due to a bad/slow connection
|
||||
/// more info: https://git.ngram.ca/OpenJam/rc-servers/issues/127
|
||||
KeybindLockout { },
|
||||
/// Lock game event expiry to currently-selected game mode for user
|
||||
/// more info: https://git.ngram.ca/OpenJam/rc-servers/issues/84
|
||||
GameModeEventLock {
|
||||
event: IntercomGameEvent,
|
||||
},
|
||||
/// Return to normal game event expiry behaviour for user
|
||||
/// more info: https://git.ngram.ca/OpenJam/rc-servers/issues/84
|
||||
GameModeEventUnlock { },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "workaround")]
|
||||
pub enum IntercomLobbyWorkaroundMessage {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(tag = "workaround")]
|
||||
pub enum IntercomWorkaroundMessage {
|
||||
Lobby(IntercomLobbyWorkaroundMessage),
|
||||
WebService(IntercomWebServiceWorkaroundMessage),
|
||||
}
|
||||
|
||||
pub fn generate_token(salt: &[u8], key: &[u8]) -> String {
|
||||
|
||||
@@ -11,10 +11,6 @@ fn fake_impl_to_db(client_emu: &crate::persist::config::ClientEmulator) -> oj_rc
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::LobbyUser for UserData {
|
||||
fn user_id(&self) -> i32 {
|
||||
self.account.id
|
||||
}
|
||||
|
||||
async fn player_data(&self, cpu_counter: &crate::cubes::CpuListParser) -> Result<crate::data::player_data::PlayerData, polariton_server::operations::SimpleOpError> {
|
||||
self.user_player_data(cpu_counter).await.map_err(|e| {
|
||||
if let Some(msg) = e.error_msg() {
|
||||
|
||||
@@ -297,7 +297,6 @@ pub enum UserRole {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait LobbyUser {
|
||||
fn user_id(&self) -> i32;
|
||||
async fn player_data(&self, cpu_counter: &crate::cubes::CpuListParser) -> Result<crate::data::player_data::PlayerData, polariton_server::operations::SimpleOpError>;
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn start_game(&self, game: GameDescriptor, players: Vec<PlayerLobbyDescriptor>, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, cpu_counter: &crate::cubes::CpuListParser, weapon_lister: &crate::cubes::WeaponListParser, team_chooser: &dyn super::TeamChooser, missing_players: usize) -> Result<FakePlayers, polariton_server::operations::SimpleOpError>;
|
||||
|
||||
Reference in New Issue
Block a user