use std::sync::Arc;
use std::sync::Weak;
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::RwLockWriteGuard;
use crate::Task;
use crate::Team;
use crate::Error;
use crate::Player;
use crate::TimeSpan;
use crate::GameType;
use crate::Universe;
use crate::Connector;
use crate::ConnectorArc;
use crate::IndexList;
use crate::Difficulty;
use crate::Tournament;
use crate::ManagedArray;
use crate::UniversalHolder;
use crate::UniversalEnumerable;
use crate::UniverseGroupFlowControl;
use crate::PerformanceRequirement;
use crate::controllable::Ship;
use crate::controllable::AnyControllable;
use crate::net::Packet;
use crate::net::BinaryReader;
use crate::net::BinaryWriter;
use crate::net::is_set_u8;
pub struct UniverseGroup {
id: u16,
name: String,
game_type: Option<GameType>,
difficulty: Difficulty,
performance_requirement: PerformanceRequirement,
max_tick_time: TimeSpan,
avg_tick_time: TimeSpan,
password_required: bool,
achievement_required: bool,
maximum_ship_level: u8,
maximum_players: u16,
max_platforms_per_player: u8,
max_probes_per_player: u8,
max_drones_per_player: u8,
max_ships_per_player: u8,
max_bases_per_player: u8,
max_platforms_per_team: u16,
max_probes_per_team: u16,
max_drones_per_team: u16,
max_ships_per_team: u16,
max_bases_per_team: u16,
kill_lonesome_units: bool,
description: String,
connector: Weak<Connector>,
universes: RwLock<UniversalHolder<Universe>>,
teams: RwLock<UniversalHolder<Team>>,
players: RwLock<ManagedArray<Arc<Player>>>,
tournament: RwLock<Option<Arc<Tournament>>>
}
impl UniverseGroup {
pub fn from_reader(connector: &Arc<Connector>, packet: &Packet) -> Result<UniverseGroup, Error> {
let reader = &mut packet.read() as &mut BinaryReader;
let name = reader.read_string()?;
let game_type = GameType::from_id(reader.read_byte()?);
let difficulty = Difficulty::from_id(reader.read_byte()?)?;
let performance_requirement = PerformanceRequirement::from_id(reader.read_byte()?)?;
let max_tick_time = TimeSpan::new(reader.read_i64()?);
let avg_tick_time = TimeSpan::new(reader.read_i64()?);
let header = reader.read_byte()?;
let password_required = is_set_u8(header, 0x01);
let achievement_required = is_set_u8(header, 0x02);
let maximum_ship_level = reader.read_unsigned_byte()?;
let maximum_players = reader.read_u16()?;
let max_platforms_per_player = reader.read_byte()?;
let max_probes_per_player = reader.read_byte()?;
let max_drones_per_player = reader.read_byte()?;
let max_ships_per_player = reader.read_byte()?;
let max_bases_per_player = reader.read_byte()?;
let max_platforms_per_team = reader.read_u16()?;
let max_probes_per_team = reader.read_u16()?;
let max_drones_per_team = reader.read_u16()?;
let max_ships_per_team = reader.read_u16()?;
let max_bases_per_team = reader.read_u16()?;
let kill_lonesome_units = reader.read_bool()?;
let description = reader.read_string()?;
let universes = RwLock::new(UniversalHolder::new(IndexList::new(false, 16)));
let teams = RwLock::new(UniversalHolder::new(IndexList::new(false, 16)));
let players = RwLock::new(ManagedArray::with_capacity(maximum_players as usize));
Ok(UniverseGroup {
connector: Arc::downgrade(connector),
id: packet.path_universe_group(),
name,
game_type,
difficulty,
performance_requirement,
max_tick_time,
avg_tick_time,
password_required,
achievement_required,
maximum_ship_level,
maximum_players,
max_platforms_per_player,
max_probes_per_player,
max_drones_per_player,
max_ships_per_player,
max_bases_per_player,
max_platforms_per_team,
max_probes_per_team,
max_drones_per_team,
max_ships_per_team,
max_bases_per_team,
kill_lonesome_units,
description,
universes,
teams,
players,
tournament: RwLock::new(None),
})
}
pub fn tournament(&self) -> Option<Arc<Tournament>> {
let tournament = self.tournament.read().unwrap();
if tournament.is_some() {
match self.connector.upgrade() {
None => {},
Some(connector) => {
connector.register_task_quitely_if_unknown(Task::UsedTournament);
}
}
};
tournament.clone()
}
pub(crate) fn set_tournament(&self, tournament: Option<Arc<Tournament>>) -> Result<(), Error> {
*self.tournament.write()? = tournament;
Ok(())
}
pub fn avatar_raw(&self) -> Result<Vec<u8>, Error> {
match self.connector.upgrade() {
None => Err(Error::ConnectorNotAvailable),
Some(connector) => {
let mut block = connector.block_manager().block()?;
let mut packet = Packet::default();
packet.set_command(0x20);
packet.set_session(block.id());
packet.set_path_universe_group(self.id);
connector.send(&packet)?;
let response = block.wait()?;
Ok(Vec::from(response.read()))
}
}
}
pub fn new_flow_control(&self) -> Result<Arc<UniverseGroupFlowControl>, Error> {
match self.connector.upgrade() {
None => Err(Error::ConnectorNotAvailable),
Some(connector) => {
let flow = connector.register_flow_control()?;
flow.setup()?;
Ok(flow)
}
}
}
pub fn register_ship(&self, class: &str, name: &str) -> Result<Arc<Ship>, Error> {
let connector = self.connector.upgrade().ok_or(Error::ConnectorNotAvailable)?;
let player = connector.player().upgrade().ok_or(Error::PlayerNotAvailable)?;
match player.universe_group().upgrade() {
None => return Err(Error::PlayerNotInUniverseGroup),
Some(group) => {
let id_other = group.id();
if id_other != self.id {
return Err(Error::PlayerAlreadyInAnotherUniverseGroup(id_other));
}
}
};
if !"@Ship".eq(class) && !Connector::check_name(class) {
return Err(Error::InvalidClass);
}
if !Connector::check_name(name) {
return Err(Error::InvalidName);
}
let mut block = connector.block_manager().block()?;
let mut packet = Packet::default();
packet.set_command(0x80);
packet.set_session(block.id());
{
let writer = packet.write() as &mut BinaryWriter;
writer.write_string(class)?;
writer.write_string(name)?;
writer.write_u8(0)?; }
connector.send(&packet)?;
let response = block.wait()?;
match connector.controllable(response.path_ship())? {
AnyControllable::Ship(ship) => Ok(ship),
_ => Err(Error::not_controllable_ship())
}
}
pub fn part(&self) -> Result<(), Error> {
let connector = self.connector.upgrade().ok_or(Error::ConnectorNotAvailable)?;
let player = connector.player().upgrade().ok_or(Error::PlayerNotAvailable)?;
match player.universe_group().upgrade() {
None => return Err(Error::PlayerNotInUniverseGroup),
Some(group) => {
let id_other = group.id();
if id_other != self.id {
return Err(Error::PlayerAlreadyInAnotherUniverseGroup(id_other));
}
}
};
if connector.has_flows()? {
return Err(Error::StillOpenFlowControlsInUniverseGroup(self.id));
}
let mut block = connector.block_manager().block()?;
let mut packet = Packet::default();
packet.set_command(0x06);
packet.set_session(block.id());
connector.send(&packet)?;
block.wait()?;
Ok(())
}
pub fn chat(&self, message: &str) -> Result<(), Error> {
if message.is_empty() || message.len() > 140 {
return Err(Error::InvalidMessage);
}
let connector = self.connector.upgrade().ok_or(Error::ConnectorNotAvailable)?;
let player = connector.player().upgrade().ok_or(Error::PlayerNotAvailable)?;
match player.universe_group().upgrade() {
None => return Err(Error::PlayerNotInUniverseGroup),
Some(group) => {
let id_other = group.id();
if id_other != self.id {
return Err(Error::PlayerAlreadyInAnotherUniverseGroup(id_other));
}
}
};
let mut block = connector.block_manager().block()?;
let mut packet = Packet::default();
packet.set_command(0x32);
packet.set_session(block.id());
{
let writer = packet.write() as &mut BinaryWriter;
writer.write_string(message)?;
}
connector.send(&packet)?;
block.wait()?;
Ok(())
}
pub fn join(&self, name: &str, team: u8, clan: Option<&str>, password: Option<&str>) -> Result<(), Error> {
let _ = self.team(team)?;
if name.is_empty() || name.len() > 140 {
return Err(Error::InvalidName);
}
let connector = self.connector.upgrade().ok_or(Error::ConnectorNotAvailable)?;
let mut block = connector.block_manager().block()?;
let mut packet = Packet::default();
packet.set_command(0x04);
packet.set_session(block.id());
packet.set_path_universe_group(self.id);
packet.set_path_sub(team);
{
let writer = packet.write() as &mut BinaryWriter;
writer.write_string(name)?;
let mut header = 0x00;
if clan.is_some() {
header |= 0x01;
}
if password.is_some() {
header |= 0x02;
}
writer.write_byte(header)?;
if let Some(c) = clan {
writer.write_string(c)?;
}
if let Some(p) = password {
writer.write_string(p)?;
}
}
connector.send(&packet)?;
block.wait()?;
Ok(())
}
pub fn id(&self) -> u16 {
self.id
}
pub fn universe(&self, index: u8) -> Weak<Universe> {
self.universes.read().unwrap().get_for_index_weak(index as usize)
}
pub(crate) fn set_universe(&self, index: u8, universe: Option<Arc<Universe>>) {
self.universes.write().unwrap().set(index as usize, universe);
}
pub fn connector(&self) -> &Weak<Connector> {
&self.connector
}
pub fn game_type(&self) -> Option<GameType> {
self.game_type
}
pub fn teams(&self) -> RwLockReadGuard<UniversalHolder<Team>> {
self.teams.read().unwrap()
}
pub fn team(&self, index: u8) -> Result<Arc<Team>, Error> {
self.teams.read()?.get_for_index(index as usize).ok_or_else(|| Error::InvalidTeam(index))
}
pub fn team_weak(&self, index: u8) -> Weak<Team> {
self.teams.read().unwrap().get_for_index_weak(index as usize)
}
pub(crate) fn set_team(&self, index: u8, team: Option<Arc<Team>>) {
self.teams.write().unwrap().set(index as usize, team);
}
pub fn avg_tick_time(&self) -> &TimeSpan {
&self.avg_tick_time
}
pub fn players(&self) -> RwLockReadGuard<ManagedArray<Arc<Player>>> {
self.players.read().unwrap()
}
pub(crate) fn players_mut(&self) -> Result<RwLockWriteGuard<ManagedArray<Arc<Player>>>, Error> {
Ok(self.players.write()?)
}
pub fn universes(&self) -> RwLockReadGuard<UniversalHolder<Universe>> {
self.universes.read().unwrap()
}
pub fn maximum_ship_level(&self) -> u8 {
self.maximum_ship_level
}
pub fn max_players(&self) -> u16 {
self.maximum_players
}
pub fn performance_requirement(&self) -> PerformanceRequirement {
self.performance_requirement
}
}
impl UniversalEnumerable for UniverseGroup {
fn name(&self) -> &str {
&self.name
}
}
impl PartialEq for UniverseGroup {
fn eq(&self, other: &UniverseGroup) -> bool {
self.id == other.id
}
}