// StarKingdoms.IO, a browser game about drifting through space
// Copyright (C) 2023 ghostly_zsh, TerraMaster85, core
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#![allow(clippy::type_complexity)] // bevy :(
#![allow(clippy::too_many_arguments)] // bevy :(
#![allow(clippy::only_used_in_recursion)] // todo: remove this
#[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
use std::net::IpAddr;
use std::num::NonZeroUsize;
use crate::mathutil::rot2d;
use crate::ws::{StkTungsteniteServerConfig, StkTungsteniteServerPlugin, WsEvent};
use bevy::math::{vec2, vec3};
use bevy::{
app::{PluginGroupBuilder, ScheduleRunnerPlugin},
ecs::event::ManualEventReader,
prelude::*,
time::TimePlugin,
};
use bevy_rapier2d::prelude::*;
use component::Input;
use component::*;
use hmac::{Hmac, Mac};
use jwt::VerifyWithKey;
use packet::*;
use rand::Rng;
use serde::{Deserialize, Serialize};
use sha2::Sha256;
use starkingdoms_common::SaveModule;
use starkingdoms_common::{pack_savefile, unpack_savefile, SaveData};
use std::f32::consts::PI;
use std::str::FromStr;
use std::time::Duration;
pub mod component;
pub mod macros;
pub mod mathutil;
pub mod packet;
pub mod ws;
const CLIENT_SCALE: f32 = 50.0;
const EARTH_SIZE: f32 = 20.0;
const MOON_SIZE: f32 = EARTH_SIZE / 4.;
const MARS_SIZE: f32 = EARTH_SIZE / 2.;
const EARTH_MASS: f32 = 10000.0;
const MOON_MASS: f32 = EARTH_MASS / 30.;
const MARS_MASS: f32 = EARTH_MASS / 8.;
const GRAVITY: f32 = 0.0002;
const PART_HALF_SIZE: f32 = 25.0;
const HEARTY_THRUSTER_FORCE: f32 = 0.3;
const LANDING_THRUSTER_FORCE: f32 = 5.;
const HEARTY_MASS: f32 = 1.0;
const CARGO_MASS: f32 = 0.5;
const HUB_MASS: f32 = 1.0;
const LANDING_THRUSTER_MASS: f32 = 0.9;
// maybe make this only cargo modules later
const FREE_MODULE_CAP: usize = 30;
struct StkPluginGroup;
#[cfg(debug_assertions)]
impl PluginGroup for StkPluginGroup {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::()
.add(TaskPoolPlugin::default())
.add(TypeRegistrationPlugin)
.add(FrameCountPlugin)
.add(TimePlugin)
.add(ScheduleRunnerPlugin::run_loop(Duration::from_millis(1)))
.add(bevy::log::LogPlugin {
level: bevy::log::Level::DEBUG,
filter: "wgpu=error,bevy_render=info,bevy_ecs=trace".to_string(),
update_subscriber: None,
})
}
}
#[cfg(not(debug_assertions))]
impl PluginGroup for StkPluginGroup {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::()
.add(TaskPoolPlugin::default())
.add(TypeRegistrationPlugin)
.add(FrameCountPlugin)
.add(TimePlugin)
.add(ScheduleRunnerPlugin::run_loop(Duration::from_millis(1)))
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserToken {
pub id: i64,
pub username: String,
pub permission_level: i32,
pub expires: std::time::SystemTime,
}
pub const REQUIRED_PERM_LEVEL: i32 = 10;
#[derive(Deserialize)]
struct KeyJson {
app_key: String,
}
fn main() {
// read the key in
let key = std::fs::read_to_string("/etc/starkingdoms/keys.json").unwrap();
let keyjson: KeyJson = serde_json::from_str(&key).unwrap();
App::new()
.insert_resource(AppKeys {
app_key: keyjson.app_key.as_bytes().to_vec(),
})
.insert_resource(StkTungsteniteServerConfig {
addr: IpAddr::from_str("0.0.0.0").unwrap(),
port: 3000,
})
.add_plugins(StkPluginGroup)
.insert_resource(RapierConfiguration {
gravity: Vect { x: 0.0, y: 0.0 },
..Default::default()
})
.init_resource::()
.add_plugins(RapierPhysicsPlugin::::pixels_per_meter(1.0))
.add_plugins(StkTungsteniteServerPlugin)
.add_systems(Startup, setup_integration_parameters)
.add_systems(Startup, spawn_planets)
.add_systems(FixedUpdate, module_spawn)
.add_systems(Update, on_message)
.add_systems(Update, on_close)
.add_systems(FixedUpdate, on_position_change)
.add_systems(
FixedUpdate,
(break_modules, gravity_update, player_input_update).chain(),
)
.add_systems(FixedUpdate, save_eligibility)
.add_systems(FixedUpdate, convert_modules)
.insert_resource(Time::::from_seconds(1.0 / 60.0))
.run();
info!("Goodbye!");
}
fn setup_integration_parameters(mut context: ResMut) {
context.integration_parameters.dt = 1.0 / 60.0;
context.integration_parameters.joint_erp = 0.2;
context.integration_parameters.erp = 0.5;
//context.integration_parameters.num_solver_iterations = NonZeroUsize::new(16).unwrap();
}
fn spawn_planets(mut commands: Commands) {
info!("Spawning planets");
let earth_pos = Transform::from_xyz(0.0, 0.0, 0.0);
commands
.spawn(PlanetBundle {
planet_type: PlanetType::Earth,
transform: TransformBundle::from(earth_pos),
})
.insert(Collider::ball(EARTH_SIZE))
.insert(AdditionalMassProperties::Mass(EARTH_MASS))
.insert(ReadMassProperties::default())
.with_children(|children| {
children
.spawn(Collider::ball(EARTH_SIZE + 0.3))
.insert(ActiveEvents::COLLISION_EVENTS)
.insert(Sensor);
})
.insert(RigidBody::Fixed);
let moon_pos = Transform::from_xyz(50.0, 0.0, 0.0);
commands
.spawn(PlanetBundle {
planet_type: PlanetType::Moon,
transform: TransformBundle::from(moon_pos),
})
.insert(Collider::ball(MOON_SIZE))
.insert(AdditionalMassProperties::Mass(MOON_MASS))
.insert(ReadMassProperties::default())
.with_children(|children| {
children
.spawn(Collider::ball(MOON_SIZE + 0.1))
.insert(ActiveEvents::COLLISION_EVENTS)
.insert(Sensor);
})
.insert(RigidBody::Fixed);
let mars_pos = Transform::from_xyz(50.0, 20.0, 0.0);
commands
.spawn(PlanetBundle {
planet_type: PlanetType::Mars,
transform: TransformBundle::from(mars_pos),
})
.insert(Collider::ball(MARS_SIZE))
.insert(AdditionalMassProperties::Mass(MARS_MASS))
.insert(ReadMassProperties::default())
.with_children(|children| {
children
.spawn(Collider::ball(MARS_SIZE + 0.1))
.insert(ActiveEvents::COLLISION_EVENTS)
.insert(Sensor);
})
.insert(RigidBody::Fixed);
}
fn module_spawn(
mut commands: Commands,
time: Res