1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Use real spawn points when available #30

This commit is contained in:
NG (Graham)
2025-07-26 11:47:05 -04:00
parent a27ae3d466
commit c6bd9e110d
13 changed files with 520 additions and 106 deletions

View File

@@ -55,14 +55,14 @@ impl GameMap {
#[inline]
pub fn as_str(&self) -> &'static str {
match self {
Self::Mars1 => "RC_Planet_Mars_01_CTF",
Self::Mars2 => "RC_Planet_Mars_02_BA",
Self::Mars3 => "RC_Planet_Mars_03_BA",
Self::Neptune1 => "RC_Planet_Neptune_01_CTF",
Self::Neptune2 => "RC_Planet_Neptune_02_BA",
Self::Neptune3 => "RC_Planet_Neptune_03_BA",
Self::Earth1 => "RC_Planet_Earth_01_BA",
Self::Earth2 => "RC_Planet_Earth_02_BA",
Self::Mars1 => "RC_Planet_Mars_01_CTF", // og flat mars
Self::Mars2 => "RC_Planet_Mars_02_BA", // the one with the bridge in the middle
Self::Mars3 => "RC_Planet_Mars_03_BA", // tharsis rift without the rift
Self::Neptune1 => "RC_Planet_Neptune_01_CTF", // og flat GJ1214b gliese lake without the lake
Self::Neptune2 => "RC_Planet_Neptune_02_BA", // the one with the cave
Self::Neptune3 => "RC_Planet_Neptune_03_BA", // spitzer dam
Self::Earth1 => "RC_Planet_Earth_01_BA", // birmingham power station
Self::Earth2 => "RC_Planet_Earth_02_BA", // vanguard
}
}
@@ -82,7 +82,7 @@ impl GameMap {
}
#[repr(u8)]
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub enum GameMode {
BattleArena = 0,
SuddenDeath = 1,

View File

@@ -14,6 +14,8 @@ pub struct BattleConfig {
pub rotation: GameEventSequence,
#[serde(default = "default_multiplayer")]
pub multiplayer: super::MultiplayerConfig,
#[serde(default = "default_maps")]
pub maps: super::MapsConfig,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
@@ -144,7 +146,7 @@ pub struct GameEvent {
}
impl GameEvent {
pub fn into_conf(self) -> crate::persist::config::GameEvent {
pub(super) fn into_conf(self) -> crate::persist::config::GameEvent {
crate::persist::config::GameEvent {
map: self.map.into_conf(),
visibility: self.visibility.into_conf(),
@@ -154,7 +156,7 @@ impl GameEvent {
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
#[derive(Serialize, Deserialize, Clone, Debug, Copy, Hash, Eq, PartialEq)]
pub enum GameMap {
// TODO put some more obvious aliases on these
Mars1,
@@ -168,7 +170,7 @@ pub enum GameMap {
}
impl GameMap {
fn into_conf(self) -> crate::persist::config::GameMap {
pub(super) fn into_conf(self) -> crate::persist::config::GameMap {
match self {
Self::Mars1 => crate::persist::config::GameMap::Mars1,
Self::Mars2 => crate::persist::config::GameMap::Mars2,
@@ -477,8 +479,14 @@ fn default_rotation() -> GameEventSequence {
fn default_multiplayer() -> super::MultiplayerConfig {
super::MultiplayerConfig {
players_per_game: 2,
players_per_game: 1,
enabled: true,
network: super::multiplayer::default_net_conf(),
}
}
fn default_maps() -> super::MapsConfig {
super::MapsConfig {
map: super::maps::default_map(),
}
}

View File

@@ -370,4 +370,40 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
fn network_config(&self) -> crate::persist::NetworkConf {
self.battle.multiplayer.network.clone()
}
fn maps(&self) -> std::collections::HashMap<super::GameMap, super::MapConfig> {
self.battle.maps.map.iter().map(|(map, conf)| {
let mut spawns = std::collections::HashMap::<u8, Vec<super::Point>>::with_capacity(2); // usually 2 teams
for point in conf.spawn_points.iter() {
if let Some(list) = spawns.get_mut(&point.team) {
list.push(super::Point {
x: point.x,
y: point.y,
z: point.z,
});
} else {
let mut list = Vec::with_capacity(10); // usually 10 spawn points (suddent death has the most)
list.push(super::Point {
x: point.x,
y: point.y,
z: point.z,
});
spawns.insert(point.team, list);
}
}
let bases = conf.bases.iter().map(|base| (base.team, super::Sphere {
radius: base.radius,
center: super::Point {
x: base.x,
y: base.y,
z: base.z,
},
})).collect();
let map_conf = super::MapConfig {
spawns,
bases,
};
(map.into_conf(), map_conf)
}).collect()
}
}

View File

@@ -2,7 +2,7 @@ mod cubes_json;
pub use cubes_json::CubeConfig;
mod traits;
pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode};
pub use traits::{ConfigProvider, CompleteCampaignProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig};
pub type ConfigImpl = CubeConfig;

View File

@@ -31,6 +31,7 @@ pub trait ConfigProvider<C: Clone> {
fn is_multiplayer_enabled(&self) -> bool;
// FIXME don't use serializable types in traits
fn network_config(&self) -> crate::persist::NetworkConf;
fn maps(&self) -> std::collections::HashMap<GameMap, MapConfig>;
}
pub struct CompleteCampaignProvider {
@@ -270,7 +271,7 @@ pub struct GameEvent {
pub auto_heal: bool,
}
#[derive(Clone, Debug, Copy)]
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub enum GameMap {
Mars1,
Mars2,
@@ -329,3 +330,22 @@ pub enum VehicleDescriptor {
}
// TODO File
}
#[derive(Clone, Debug)]
pub struct Point {
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Clone, Debug)]
pub struct Sphere {
pub radius: f32,
pub center: Point,
}
#[derive(Clone, Debug)]
pub struct MapConfig {
pub spawns: std::collections::HashMap<u8, Vec<Point>>, // team -> points
pub bases: std::collections::HashMap<u8, Sphere>, // team -> base
}

211
rc_core/src/persist/maps.rs Normal file
View File

@@ -0,0 +1,211 @@
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MapsConfig {
#[serde(default = "default_map")]
pub map: std::collections::HashMap<super::combat::GameMap, MapConfig>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MapConfig {
pub spawn_points: Vec<SpawnPoint>,
pub bases: Vec<CaptureBase>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SpawnPoint {
pub team: u8,
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CaptureBase {
pub team: u8,
pub x: f32,
pub y: f32,
pub z: f32,
pub radius: f32,
}
pub(super) fn default_map() -> std::collections::HashMap<super::combat::GameMap, MapConfig> {
let mut map = std::collections::HashMap::with_capacity(9);
let coords_t0 = corner_to_center((6.60, 4.09, 20.3), 10.0);
let coords_t1 = corner_to_center((364.60, 10.63, 372.20), 10.0);
map.insert(super::combat::GameMap::Mars1, MapConfig {
spawn_points: vec![
// team 0
SpawnPoint {
team: 0,
x: 32.07,
y: 1.73,
z: 49.75,
},
SpawnPoint {
team: 0,
x: 39.20,
y: 1.73,
z: 40.21,
},
SpawnPoint {
team: 0,
x: 21.14,
y: 1.73,
z: 44.16,
},
SpawnPoint {
team: 0,
x: 32.50,
y: 1.73,
z: 30.66,
},
SpawnPoint {
team: 0,
x: 31.1,
y: 1.73,
z: 6.80,
},
SpawnPoint {
team: 0,
x: 43.40,
y: 1.73,
z: 8.60,
},
SpawnPoint {
team: 0,
x: 36.00,
y: 1.73,
z: 18.70,
},
SpawnPoint {
team: 0,
x: 3.00,
y: 1.73,
z: 57.4,
},
SpawnPoint {
team: 0,
x: 9.90,
y: 1.73,
z: 47.90,
},
SpawnPoint {
team: 0,
x: -2.40,
y: 1.73,
z: 46.40,
},
// team 1
SpawnPoint {
team: 1,
x: 346.09,
y: 8.10,
z: 339.18,
},
SpawnPoint {
team: 1,
x: 337.10,
y: 8.10,
z: 346.80,
},
SpawnPoint {
team: 1,
x: 356.10,
y: 8.10,
z: 344.90,
},
SpawnPoint {
team: 1,
x: 340.10,
y: 8.10,
z: 358.20,
},
SpawnPoint {
team: 1,
x: 327.15,
y: 8.10,
z: 381.87,
},
SpawnPoint {
team: 1,
x: 339.10,
y: 8.10,
z: 383.60,
},
SpawnPoint {
team: 1,
x: 334.80,
y: 8.10,
z: 372.40,
},
SpawnPoint {
team: 1,
x: 382.50,
y: 8.10,
z: 335.10,
},
SpawnPoint {
team: 1,
x: 373.10,
y: 8.10,
z: 342.40,
},
SpawnPoint {
team: 1,
x: 384.50,
y: 8.10,
z: 346.80,
},
],
bases: vec![
CaptureBase {
team: 0,
x: coords_t0.0,
y: coords_t0.1,
z: coords_t0.2,
radius: 10.0,
},
CaptureBase {
team: 1,
x: coords_t1.0,
y: coords_t1.1,
z: coords_t1.2,
radius: 10.0,
},
],
});
map.insert(super::combat::GameMap::Mars2, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Mars3, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Neptune1, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Neptune2, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Neptune3, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Earth1, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map.insert(super::combat::GameMap::Earth2, MapConfig {
spawn_points: vec![],
bases: vec![],
});
map
}
const fn corner_to_center(corner: (f32, f32, f32), radius: f32) -> (f32, f32, f32) {
(corner.0 + radius, corner.1, corner.2 + radius)
}

View File

@@ -38,6 +38,9 @@ pub use vehicle_factory::{FactoryConfig, AdapterSettings, ArcFactorySettings};
mod multiplayer;
pub use multiplayer::{MultiplayerConfig, NetworkConf};
mod maps;
pub use maps::{MapsConfig, MapConfig};
pub(self) const VALID_ROBOT: &[u8] = &[64,
0,
0,

View File

@@ -1367,4 +1367,32 @@ impl super::MultiplayerUser for UserData {
})
}
}
async fn game_info(&self, guid: &str) -> Result<Option<super::GameDescriptor>, super::MultiplayerError> {
if let Some(guid) = crate::persist::user::str_to_i64(guid) {
let game_opt = self.db.game_by_guid(guid.to_owned()).await
.map_err(|e| {
log::error!("Failed to retrieve game {} with user {}: {}", guid, self.account.id, e);
super::MultiplayerError {
code: super::MultiplayerErrorCode::CustomString,
message: format!("Failed to retrieve game {}: {}", guid, e),
}
})?;
Ok(game_opt.map(|game| super::GameDescriptor {
guid: crate::persist::user::i64_as_uuid_str(game.guid),
map: game.map,
mode: crate::data::game_mode::GameMode::from_db(game.mode),
visibility: crate::data::game_mode::MapVisibility::from_db(game.visibility),
auto_heal: game.auto_heal,
is_ranked: matches!(game.variant, oj_rc_database::schema::multiplayer_game::GameType::Ranked),
is_custom: matches!(game.variant, oj_rc_database::schema::multiplayer_game::GameType::Custom),
is_complete: game.is_complete,
}))
} else {
Err(super::MultiplayerError {
code: super::MultiplayerErrorCode::IncorrectGameGuid,
message: format!("Failed to parse game GUID {}", guid),
})
}
}
}

View File

@@ -320,4 +320,5 @@ pub trait MultiplayerUser {
async fn current_game(&self) -> Result<Option<GameDescriptor>, MultiplayerError>;
async fn game_players(&self, guid: &str) -> Result<Vec<PlayerDescriptor>, MultiplayerError>;
async fn complete_game(&self, guid: &str) -> Result<(), MultiplayerError>;
async fn game_info(&self, guid: &str) -> Result<Option<GameDescriptor>, MultiplayerError>;
}