mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add pit spawn points #34
This commit is contained in:
@@ -14543,6 +14543,10 @@
|
|||||||
{
|
{
|
||||||
"message": "Stop Killing Games",
|
"message": "Stop Killing Games",
|
||||||
"duration": 20
|
"duration": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"message": "Also check out RC15",
|
||||||
|
"duration": 20
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ fn default_rotation() -> GameEventSequence {
|
|||||||
auto_heal: true,
|
auto_heal: true,
|
||||||
},
|
},
|
||||||
multiplayer: GameEvent {
|
multiplayer: GameEvent {
|
||||||
map: GameMap::Neptune3,
|
map: GameMap::Earth1,
|
||||||
visibility: GameVisibility::Good,
|
visibility: GameVisibility::Good,
|
||||||
mode: GameType::Pit,
|
mode: GameType::Pit,
|
||||||
auto_heal: true,
|
auto_heal: true,
|
||||||
|
|||||||
@@ -385,21 +385,30 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
|||||||
fn maps(&self) -> std::collections::HashMap<super::GameMap, super::MapConfig> {
|
fn maps(&self) -> std::collections::HashMap<super::GameMap, super::MapConfig> {
|
||||||
self.battle.maps.map.iter().map(|(map, conf)| {
|
self.battle.maps.map.iter().map(|(map, conf)| {
|
||||||
let mut spawns = std::collections::HashMap::<u8, Vec<super::Point>>::with_capacity(2); // usually 2 teams
|
let mut spawns = std::collections::HashMap::<u8, Vec<super::Point>>::with_capacity(2); // usually 2 teams
|
||||||
|
let mut pit_spawns = Vec::default();
|
||||||
for point in conf.spawn_points.iter() {
|
for point in conf.spawn_points.iter() {
|
||||||
if let Some(list) = spawns.get_mut(&point.team) {
|
if let Some(point_team) = &point.team {
|
||||||
list.push(super::Point {
|
if let Some(list) = spawns.get_mut(point_team) {
|
||||||
x: point.x,
|
list.push(super::Point {
|
||||||
y: point.y,
|
x: point.x,
|
||||||
z: point.z,
|
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);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut list = Vec::with_capacity(10); // usually 10 spawn points (suddent death has the most)
|
pit_spawns.push(super::Point {
|
||||||
list.push(super::Point {
|
|
||||||
x: point.x,
|
x: point.x,
|
||||||
y: point.y,
|
y: point.y,
|
||||||
z: point.z,
|
z: point.z,
|
||||||
});
|
});
|
||||||
spawns.insert(point.team, list);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let bases = conf.bases.iter().map(|base| (base.team, (super::Sphere {
|
let bases = conf.bases.iter().map(|base| (base.team, (super::Sphere {
|
||||||
@@ -425,6 +434,7 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
|||||||
};
|
};
|
||||||
let map_conf = super::MapConfig {
|
let map_conf = super::MapConfig {
|
||||||
spawns,
|
spawns,
|
||||||
|
pit_spawns,
|
||||||
bases,
|
bases,
|
||||||
capture_points,
|
capture_points,
|
||||||
equalizer,
|
equalizer,
|
||||||
|
|||||||
@@ -360,6 +360,7 @@ pub struct Sphere {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MapConfig {
|
pub struct MapConfig {
|
||||||
pub spawns: std::collections::HashMap<u8, Vec<Point>>, // team -> points
|
pub spawns: std::collections::HashMap<u8, Vec<Point>>, // team -> points
|
||||||
|
pub pit_spawns: Vec<Point>,
|
||||||
pub bases: std::collections::HashMap<u8, (Sphere, f32)>, // team -> (base, capture speed)
|
pub bases: std::collections::HashMap<u8, (Sphere, f32)>, // team -> (base, capture speed)
|
||||||
pub capture_points: Vec<(Sphere, f32)>, // (capture point, capture speed)
|
pub capture_points: Vec<(Sphere, f32)>, // (capture point, capture speed)
|
||||||
pub equalizer: Point,
|
pub equalizer: Point,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -245,6 +245,7 @@ mod _broadcast_impls {
|
|||||||
impl Broadcastable for rlnl::events::sync::GetEqualizer {}
|
impl Broadcastable for rlnl::events::sync::GetEqualizer {}
|
||||||
impl Broadcastable for rlnl::events::sync::FusionShieldState {}
|
impl Broadcastable for rlnl::events::sync::FusionShieldState {}
|
||||||
impl Broadcastable for rlnl::events::sync::EqualizerNotification {}
|
impl Broadcastable for rlnl::events::sync::EqualizerNotification {}
|
||||||
|
impl Broadcastable for rlnl::events::sync::SpawnPoint {}
|
||||||
impl Broadcastable for rlnl::events::GameTime {}
|
impl Broadcastable for rlnl::events::GameTime {}
|
||||||
impl Broadcastable for rlnl::events::ingame::TeamBaseState {}
|
impl Broadcastable for rlnl::events::ingame::TeamBaseState {}
|
||||||
impl Broadcastable for rlnl::events::ingame::GameEnd {}
|
impl Broadcastable for rlnl::events::ingame::GameEnd {}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ impl GameMatches {
|
|||||||
log::warn!("No configuration found for map {}, game {} may not work correctly", game_info.map, guid);
|
log::warn!("No configuration found for map {}, game {} may not work correctly", game_info.map, guid);
|
||||||
oj_rc_core::persist::config::MapConfig {
|
oj_rc_core::persist::config::MapConfig {
|
||||||
spawns: std::collections::HashMap::default(),
|
spawns: std::collections::HashMap::default(),
|
||||||
|
pit_spawns: Vec::default(),
|
||||||
bases: std::collections::HashMap::default(),
|
bases: std::collections::HashMap::default(),
|
||||||
capture_points: Vec::default(),
|
capture_points: Vec::default(),
|
||||||
equalizer: oj_rc_core::persist::config::Point {
|
equalizer: oj_rc_core::persist::config::Point {
|
||||||
|
|||||||
@@ -1073,6 +1073,8 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
&connection.connection)
|
&connection.connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let spawn_data_already_handled = extra_packets.iter().any(|packet| matches!(packet.event, rlnl::event_code::NetworkEvent::FreeSpawnPoint));
|
||||||
|
|
||||||
for packet in extra_packets {
|
for packet in extra_packets {
|
||||||
sender.send_data(
|
sender.send_data(
|
||||||
&*packet.data,
|
&*packet.data,
|
||||||
@@ -1096,66 +1098,68 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
literustlib::packet::Property::ReliableOrdered,
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
&connection.connection)
|
&connection.connection)
|
||||||
.await?;
|
.await?;
|
||||||
if map.spawns.is_empty() {
|
if !spawn_data_already_handled {
|
||||||
// fallback
|
if map.spawns.is_empty() {
|
||||||
for i in 0..num_players {
|
|
||||||
sender.send_data(
|
|
||||||
&rlnl::events::sync::SpawnPoint {
|
|
||||||
pos: rlnl::types::PosQuatPair {
|
|
||||||
pos: rlnl::types::CompressedVec3::from((10.0 * (i as f32), 100.0, 10.0 * (i as f32))),
|
|
||||||
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
|
||||||
},
|
|
||||||
owner: i,
|
|
||||||
},
|
|
||||||
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
|
||||||
literustlib::packet::Property::ReliableOrdered,
|
|
||||||
&connection.connection)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut last_spawn_point = std::collections::HashMap::with_capacity(2); // team -> last index
|
|
||||||
for player in players.iter() {
|
|
||||||
let team = player.team as u8;
|
|
||||||
if let Some(team_points) = map.spawns.get(&team) {
|
|
||||||
if !team_points.is_empty() {
|
|
||||||
let spawn_index = if let Some(last_spawn_i) = last_spawn_point.get_mut(&team) {
|
|
||||||
*last_spawn_i = (*last_spawn_i + 1) % team_points.len();
|
|
||||||
*last_spawn_i
|
|
||||||
} else {
|
|
||||||
last_spawn_point.insert(team, 0usize);
|
|
||||||
0
|
|
||||||
};
|
|
||||||
let spawn = &team_points[spawn_index];
|
|
||||||
sender.send_data(
|
|
||||||
&rlnl::events::sync::SpawnPoint {
|
|
||||||
pos: rlnl::types::PosQuatPair {
|
|
||||||
pos: rlnl::types::CompressedVec3::from((spawn.x, spawn.y, spawn.z)),
|
|
||||||
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
|
||||||
},
|
|
||||||
owner: player.player_id,
|
|
||||||
},
|
|
||||||
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
|
||||||
literustlib::packet::Property::ReliableOrdered,
|
|
||||||
&connection.connection)
|
|
||||||
.await?;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fallback
|
// fallback
|
||||||
log::warn!("No spawn point found for player {} on team {}, using bad fallback", player.player_id, team);
|
for i in 0..num_players {
|
||||||
sender.send_data(
|
sender.send_data(
|
||||||
&rlnl::events::sync::SpawnPoint {
|
&rlnl::events::sync::SpawnPoint {
|
||||||
pos: rlnl::types::PosQuatPair {
|
pos: rlnl::types::PosQuatPair {
|
||||||
pos: rlnl::types::CompressedVec3::from((10.0 * (player.player_id as f32), 100.0, 10.0 * (team as f32) + 10.0)),
|
pos: rlnl::types::CompressedVec3::from((10.0 * (i as f32), 100.0, 10.0 * (i as f32))),
|
||||||
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: i,
|
||||||
},
|
},
|
||||||
owner: player.player_id,
|
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
||||||
},
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
&connection.connection)
|
||||||
literustlib::packet::Property::ReliableOrdered,
|
.await?;
|
||||||
&connection.connection)
|
}
|
||||||
.await?;
|
} else {
|
||||||
|
let mut last_spawn_point = std::collections::HashMap::with_capacity(2); // team -> last index
|
||||||
|
for player in players.iter() {
|
||||||
|
let team = player.team as u8;
|
||||||
|
if let Some(team_points) = map.spawns.get(&team) {
|
||||||
|
if !team_points.is_empty() {
|
||||||
|
let spawn_index = if let Some(last_spawn_i) = last_spawn_point.get_mut(&team) {
|
||||||
|
*last_spawn_i = (*last_spawn_i + 1) % team_points.len();
|
||||||
|
*last_spawn_i
|
||||||
|
} else {
|
||||||
|
last_spawn_point.insert(team, 0usize);
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let spawn = &team_points[spawn_index];
|
||||||
|
sender.send_data(
|
||||||
|
&rlnl::events::sync::SpawnPoint {
|
||||||
|
pos: rlnl::types::PosQuatPair {
|
||||||
|
pos: rlnl::types::CompressedVec3::from((spawn.x, spawn.y, spawn.z)),
|
||||||
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: player.player_id,
|
||||||
|
},
|
||||||
|
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
||||||
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
|
&connection.connection)
|
||||||
|
.await?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fallback
|
||||||
|
log::warn!("No spawn point found for player {} on team {}, using bad fallback", player.player_id, team);
|
||||||
|
sender.send_data(
|
||||||
|
&rlnl::events::sync::SpawnPoint {
|
||||||
|
pos: rlnl::types::PosQuatPair {
|
||||||
|
pos: rlnl::types::CompressedVec3::from((10.0 * (player.player_id as f32), 100.0, 10.0 * (team as f32) + 10.0)),
|
||||||
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: player.player_id,
|
||||||
|
},
|
||||||
|
rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
||||||
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
|
&connection.connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::matches::CustomGameLogic;
|
use crate::matches::CustomGameLogic;
|
||||||
|
|
||||||
struct WinTracker {
|
struct WinTracker {
|
||||||
@@ -146,10 +148,11 @@ pub struct PitLogic {
|
|||||||
win_tracking: WinTracker,
|
win_tracking: WinTracker,
|
||||||
settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>,
|
settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>,
|
||||||
timer_task: tokio::sync::Mutex<Option<tokio::task::JoinHandle<()>>>,
|
timer_task: tokio::sync::Mutex<Option<tokio::task::JoinHandle<()>>>,
|
||||||
|
initial_spawns: Vec<(u8, oj_rc_core::persist::config::Point)>, // (player_id, spawn_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PitLogic {
|
impl PitLogic {
|
||||||
pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, _map: &oj_rc_core::persist::config::MapConfig, players: &[oj_rc_core::persist::user::PlayerDescriptor], pit_settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>) -> Self {
|
pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, map: &oj_rc_core::persist::config::MapConfig, players: &[oj_rc_core::persist::user::PlayerDescriptor], pit_settings: std::sync::Arc<oj_rc_core::persist::config::PitSettings>) -> Self {
|
||||||
PitLogic {
|
PitLogic {
|
||||||
respawn_full_heal_duration: config.respawn_full_heal_duration,
|
respawn_full_heal_duration: config.respawn_full_heal_duration,
|
||||||
respawn_heal_duration: config.respawn_heal_duration,
|
respawn_heal_duration: config.respawn_heal_duration,
|
||||||
@@ -157,6 +160,7 @@ impl PitLogic {
|
|||||||
win_tracking: WinTracker::new(),
|
win_tracking: WinTracker::new(),
|
||||||
timer_task: tokio::sync::Mutex::new(None),
|
timer_task: tokio::sync::Mutex::new(None),
|
||||||
settings: pit_settings,
|
settings: pit_settings,
|
||||||
|
initial_spawns: Self::generate_first_spawns(map, players),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +234,69 @@ impl PitLogic {
|
|||||||
self.do_leader_update(generic, killer, victim).await;
|
self.do_leader_update(generic, killer, victim).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn choose_spawn_point(map_config: &oj_rc_core::persist::config::MapConfig, player_id: u8) -> (Option<usize>, oj_rc_core::persist::config::Point) {
|
||||||
|
if map_config.pit_spawns.is_empty() {
|
||||||
|
(None, oj_rc_core::persist::config::Point {
|
||||||
|
x: 10.0 * (player_id as f32),
|
||||||
|
y: 100.0,
|
||||||
|
z: 10.0,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let spawn_index = {
|
||||||
|
rand::rng().random_range(0..map_config.pit_spawns.len())
|
||||||
|
};
|
||||||
|
(Some(spawn_index), map_config.pit_spawns[spawn_index].clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_first_spawns(map_config: &oj_rc_core::persist::config::MapConfig, players: &[oj_rc_core::persist::user::PlayerDescriptor]) -> Vec<(u8, oj_rc_core::persist::config::Point)> {
|
||||||
|
if map_config.pit_spawns.is_empty() {
|
||||||
|
log::warn!("Map is missing pit spawn points, spawn points will be (poorly) generated");
|
||||||
|
}
|
||||||
|
let mut spawns = Vec::with_capacity(players.len());
|
||||||
|
let mut seen_spawns = std::collections::HashSet::new();
|
||||||
|
for player in players {
|
||||||
|
'choose_loop: loop {
|
||||||
|
let (spawn_i, spawn_point) = Self::choose_spawn_point(map_config, player.player_id);
|
||||||
|
if let Some(spawn_i) = spawn_i {
|
||||||
|
if seen_spawns.contains(&spawn_i) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
seen_spawns.insert(spawn_i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawns.push((player.player_id, spawn_point));
|
||||||
|
/*spawns.push(crate::matches::engine::RlnlPacket {
|
||||||
|
event: rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
||||||
|
property: literustlib::packet::Property::ReliableOrdered,
|
||||||
|
data: Box::new(rlnl::events::sync::SpawnPoint {
|
||||||
|
pos: rlnl::types::PosQuatPair {
|
||||||
|
pos: rlnl::types::CompressedVec3::from((spawn_point.x, spawn_point.y, spawn_point.z)),
|
||||||
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: player_i as u8,
|
||||||
|
})
|
||||||
|
});*/
|
||||||
|
break 'choose_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spawns
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial_spawns_to_packets(&self) -> Vec<crate::matches::RlnlPacket> {
|
||||||
|
self.initial_spawns.iter().map(|(player_id, spawn_point)| crate::matches::engine::RlnlPacket {
|
||||||
|
event: rlnl::event_code::NetworkEvent::FreeSpawnPoint,
|
||||||
|
property: literustlib::packet::Property::ReliableOrdered,
|
||||||
|
data: Box::new(rlnl::events::sync::SpawnPoint {
|
||||||
|
pos: rlnl::types::PosQuatPair {
|
||||||
|
pos: rlnl::types::CompressedVec3::from((spawn_point.x, spawn_point.y, spawn_point.z)),
|
||||||
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: *player_id,
|
||||||
|
})
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
async fn do_respawn_tasks(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, player_id: u8) {
|
async fn do_respawn_tasks(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, player_id: u8) {
|
||||||
log::info!("Handling respawn player {} in game {}", player_id, generic.game_guid());
|
log::info!("Handling respawn player {} in game {}", player_id, generic.game_guid());
|
||||||
let respawn_time = std::time::Duration::from_secs(self.settings.respawn_time_seconds);
|
let respawn_time = std::time::Duration::from_secs(self.settings.respawn_time_seconds);
|
||||||
@@ -248,25 +315,7 @@ impl PitLogic {
|
|||||||
&respawn_payload,
|
&respawn_payload,
|
||||||
true
|
true
|
||||||
).await;
|
).await;
|
||||||
// FIXME use full map spawns instead of team base spawns
|
let spawn_point = Self::choose_spawn_point(&generic.map_config, player_id).1;
|
||||||
let spawn_point = if let Some(team_spawns) = generic.map_config.spawns.get(&0) {
|
|
||||||
if team_spawns.is_empty() {
|
|
||||||
oj_rc_core::persist::config::Point {
|
|
||||||
x: 10.0 * (player_id as f32),
|
|
||||||
y: 100.0,
|
|
||||||
z: 10.0,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let index = (player_id as usize) % team_spawns.len();
|
|
||||||
team_spawns[index].clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
oj_rc_core::persist::config::Point {
|
|
||||||
x: 10.0 * (player_id as f32),
|
|
||||||
y: 100.0,
|
|
||||||
z: 10.0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let connections = generic.users.read().await.values().map(|player_info| player_info.connection.clone()).collect();
|
let connections = generic.users.read().await.values().map(|player_info| player_info.connection.clone()).collect();
|
||||||
tokio::task::spawn(Self::respawn_player_after(respawn_timestamp, connections, spawn_point, player_id));
|
tokio::task::spawn(Self::respawn_player_after(respawn_timestamp, connections, spawn_point, player_id));
|
||||||
}
|
}
|
||||||
@@ -301,6 +350,7 @@ impl CustomGameLogic for PitLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn on_player_end(&self, _generic: &crate::matches::GenericGamemodeEngine<Self>, _player: &crate::matches::generic::UserConnection) -> bool {
|
async fn on_player_end(&self, _generic: &crate::matches::GenericGamemodeEngine<Self>, _player: &crate::matches::generic::UserConnection) -> bool {
|
||||||
|
// TODO handle win condition when only one player remains
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +391,8 @@ impl CustomGameLogic for PitLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn extra_sync_events(&self, _generic: &crate::matches::GenericGamemodeEngine<Self>, _player: &crate::matches::generic::UserConnection) -> Vec<crate::matches::RlnlPacket> {
|
async fn extra_sync_events(&self, _generic: &crate::matches::GenericGamemodeEngine<Self>, _player: &crate::matches::generic::UserConnection) -> Vec<crate::matches::RlnlPacket> {
|
||||||
vec![
|
let mut initial_spawn_packets = self.initial_spawns_to_packets();
|
||||||
|
initial_spawn_packets.push(
|
||||||
crate::matches::RlnlPacket {
|
crate::matches::RlnlPacket {
|
||||||
event: rlnl::event_code::NetworkEvent::GameModeSettings,
|
event: rlnl::event_code::NetworkEvent::GameModeSettings,
|
||||||
property: literustlib::packet::Property::ReliableOrdered,
|
property: literustlib::packet::Property::ReliableOrdered,
|
||||||
@@ -350,7 +401,8 @@ impl CustomGameLogic for PitLogic {
|
|||||||
respawn_full_heal_duration: self.respawn_full_heal_duration,
|
respawn_full_heal_duration: self.respawn_full_heal_duration,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]
|
);
|
||||||
|
initial_spawn_packets
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_countdown_start(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, game_start: chrono::DateTime<chrono::Utc>) -> bool {
|
async fn on_countdown_start(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, game_start: chrono::DateTime<chrono::Utc>) -> bool {
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ LOGIN_MESSAGES = [
|
|||||||
"Warning, live without warning\nI say, warning, live without warning\nWithout, all right",
|
"Warning, live without warning\nI say, warning, live without warning\nWithout, all right",
|
||||||
"Spitzer Damn!",
|
"Spitzer Damn!",
|
||||||
"Stop Killing Games",
|
"Stop Killing Games",
|
||||||
|
"Also check out RC15",
|
||||||
]
|
]
|
||||||
|
|
||||||
def guess_category(name: str, sprite: str) -> str:
|
def guess_category(name: str, sprite: str) -> str:
|
||||||
|
|||||||
84
utils/generate_sub_spawns.py
Executable file
84
utils/generate_sub_spawns.py
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
import requests
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
def print_transform(child_json):
|
||||||
|
local_x = child_json["m_LocalPosition"]["m_X"]
|
||||||
|
local_y = child_json["m_LocalPosition"]["m_Y"]
|
||||||
|
local_z = child_json["m_LocalPosition"]["m_Z"]
|
||||||
|
rot_w = child_json["m_LocalRotation"]["m_W"]
|
||||||
|
rot_x = child_json["m_LocalRotation"]["m_X"]
|
||||||
|
rot_y = child_json["m_LocalRotation"]["m_Y"]
|
||||||
|
rot_z = child_json["m_LocalRotation"]["m_Z"]
|
||||||
|
# valid Rust code (to be inserted into a vec![here])
|
||||||
|
print(f"""SpawnPoint {{
|
||||||
|
team: None,
|
||||||
|
x: {local_x:.3f},
|
||||||
|
y: {local_y:.3f},
|
||||||
|
z: {local_z:.3f},
|
||||||
|
}}/*.with_rotation(num_quaternion::Quaternion {{
|
||||||
|
x: {rot_x:.6f},
|
||||||
|
y: {rot_y:.6f},
|
||||||
|
z: {rot_z:.6f},
|
||||||
|
w: {rot_w:.6f},
|
||||||
|
}})*/,""")
|
||||||
|
|
||||||
|
def gen_by_children(path: str, start: int, end: int):
|
||||||
|
path_json = json.loads(path)
|
||||||
|
url_path = str(path)
|
||||||
|
if "\"" in path:
|
||||||
|
url_path = urllib.parse.quote(path)
|
||||||
|
asset_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
asset_json = asset_resp.json()
|
||||||
|
if end is None:
|
||||||
|
end = len(asset_json["m_Children"])
|
||||||
|
for (i, child) in enumerate(asset_json["m_Children"][start:end]):
|
||||||
|
#print(i, child)
|
||||||
|
path_json["D"] = child["m_PathID"]
|
||||||
|
url_path = urllib.parse.quote(json.dumps(path_json))
|
||||||
|
child_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
child_json = child_resp.json()
|
||||||
|
print_transform(child_json)
|
||||||
|
|
||||||
|
def gen_by_mono(path: str, start: int, end: int):
|
||||||
|
path_json = json.loads(path)
|
||||||
|
url_path = str(path)
|
||||||
|
if "\"" in path:
|
||||||
|
url_path = urllib.parse.quote(path)
|
||||||
|
asset_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
asset_json = asset_resp.json()
|
||||||
|
points = asset_json["m_Structure"]["spawningPoints"]
|
||||||
|
if end is None:
|
||||||
|
end = len(points)
|
||||||
|
for (i, child) in enumerate(points):
|
||||||
|
#print(i, child)
|
||||||
|
path_json["D"] = child["m_PathID"]
|
||||||
|
url_path = urllib.parse.quote(json.dumps(path_json))
|
||||||
|
gameobj_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
gameobj_json = gameobj_resp.json()
|
||||||
|
path_json["D"] = gameobj_json["m_GameObject"]["m_PathID"]
|
||||||
|
url_path = urllib.parse.quote(json.dumps(path_json))
|
||||||
|
point_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
point_json = point_resp.json()
|
||||||
|
path_json["D"] = point_json["m_Components"][0]["m_Component"]["m_PathID"]
|
||||||
|
url_path = urllib.parse.quote(json.dumps(path_json))
|
||||||
|
child_resp = requests.get(f"http://127.0.0.1:38723/Assets/Json?Path={url_path}")
|
||||||
|
child_json = child_resp.json()
|
||||||
|
print_transform(child_json)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--start", type=int, default=0)
|
||||||
|
parser.add_argument("--end", type=int, default=None)
|
||||||
|
parser.add_argument("--mono", action='store_true')
|
||||||
|
parser.add_argument("initial_path")
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.mono:
|
||||||
|
# this works better
|
||||||
|
gen_by_mono(args.initial_path, args.start, args.end)
|
||||||
|
else:
|
||||||
|
# maybe for desperate measures
|
||||||
|
gen_by_children(args.initial_path, args.start, args.end)
|
||||||
Reference in New Issue
Block a user