~starkingdoms/starkingdoms

46986798a547b73e504b8bb9c0898bd876cb8627 — ghostlyzsh 2 years ago 73ab0fe + 87665fc
Merge commit 'HEAD@{1}'
M client/src/gateway.ts => client/src/gateway.ts +6 -1
@@ 14,6 14,8 @@ import {
    MessageS2CGoodbye_packetInfo,
    MessageS2CHello,
    MessageS2CHello_packetInfo,
    MessageS2CModulesUpdate,
    MessageS2CModulesUpdate_packetInfo,
    MessageS2CPlanetData, MessageS2CPlanetData_packetInfo,
    MessageS2CPlayersUpdate,
    MessageS2CPlayersUpdate_packetInfo,


@@ 68,7 70,7 @@ export async function gateway_connect(gateway_url: string, username: string): Ga
    client.ping_timeout = setTimeout(ping_fn, 5 * 1000);

    let handshake_start_msg = MessageC2SHello.encode({
        version: 1,
        version: 3,
        requestedUsername: username,
        nextState: State.Play
    }).finish();


@@ 143,6 145,9 @@ export async function gateway_connect(gateway_url: string, username: string): Ga
            } else if (pkt_id == MessageS2CPlanetData_packetInfo.type) {
                let pkt = MessageS2CPlanetData.decode(pkt_data);
                global.planets = pkt.planets;
            } else if (pkt_id == MessageS2CModulesUpdate_packetInfo.type) {
                let pkt = MessageS2CModulesUpdate.decode(pkt_data);
                global.modules = pkt.modules;
            } else {
                logger.warn(`server sent unexpected packet ${pkt_id} for state Play`);
            }

M client/src/index.ts => client/src/index.ts +37 -1
@@ 2,6 2,7 @@ import {Logger, logSetup} from "./logger";
import {gateway_connect, GatewayClient} from "./gateway";
import {Player} from "./protocol/player";
import {Planet, PlanetType} from "./protocol/planet";
import {Module, ModuleType} from "./protocol/module";
import {
    MessageC2SAuthenticateAndBeamOut,
    MessageC2SAuthenticateAndBeamOut_packetInfo,


@@ 17,6 18,7 @@ export interface GlobalData {
    client: GatewayClient | null,
    players: Player[],
    planets: Planet[],
    modules: Module[],
    me: Player | null,
    canvas: HTMLCanvasElement,
    spritesheet_img: HTMLImageElement | null,


@@ 38,6 40,7 @@ export const global: GlobalData = {
    client: null,
    players: [],
    planets: [],
    modules: [],
    me: null,
    canvas: <HTMLCanvasElement>document.getElementById("canvas"),
    spritesheet_img: null,


@@ 207,6 210,29 @@ async function client_main(server: string, username: string, texture_quality: st
            }
        }

        for (let i = 0; i < global.modules.length; i++) {
            let module = global.modules[i];
            console.log(module);
            // @ts-ignore
            let tex = global.spritesheet!["frames"][module_type_to_tex_id(module.moduleType)];

            global.context.save();

            global.context.rotate(module.rotation);

            global.context.translate(module.x, module.y);

            global.context.drawImage(global.spritesheet_img!,
                                     tex.frame.x,
                                     tex.frame.y,
                                     tex.frame.w,
                                     tex.frame.h,
                                     (module.x - 25 - global.me?.x!),
                                     (module.y - 25 - global.me?.y!), 50, 50);

            global.context.restore();
        }

        for (let i = 0; i < global.players.length; i++) {
            let player = global.players[i];
            // @ts-ignore


@@ 253,4 279,14 @@ function planet_type_to_tex_id(ty: PlanetType): string {
        return "moon.png"
    }
    return "unknown.png"
}
\ No newline at end of file
}
function module_type_to_tex_id(ty: ModuleType): string {
    if (ty == ModuleType.Cargo) {
        return "cargo_off.png"
    } else if (ty == ModuleType.LandingThruster) {
        return "landingthruster_off.png"
    } else if (ty == ModuleType.Hub) {
        return "hub_off.png"
    }
    return "unknown.png"
}

M client/src/protocol/message_c2s.ts => client/src/protocol/message_c2s.ts +29 -1
@@ 12,6 12,8 @@ export interface MessageC2SHello {
  requestedUsername: string;
  /** The state the connection will go into after the handshake. */
  nextState: State;
  token?: string | undefined;
  user?: string | undefined;
}

export enum MessageC2SHello_packetInfo {


@@ 244,7 246,7 @@ export function messageC2SAuthenticateAndBeamOut_packetInfoToJSON(
}

function createBaseMessageC2SHello(): MessageC2SHello {
  return { version: 0, requestedUsername: "", nextState: 0 };
  return { version: 0, requestedUsername: "", nextState: 0, token: undefined, user: undefined };
}

export const MessageC2SHello = {


@@ 258,6 260,12 @@ export const MessageC2SHello = {
    if (message.nextState !== 0) {
      writer.uint32(24).int32(message.nextState);
    }
    if (message.token !== undefined) {
      writer.uint32(34).string(message.token);
    }
    if (message.user !== undefined) {
      writer.uint32(42).string(message.user);
    }
    return writer;
  },



@@ 289,6 297,20 @@ export const MessageC2SHello = {

          message.nextState = reader.int32() as any;
          continue;
        case 4:
          if (tag != 34) {
            break;
          }

          message.token = reader.string();
          continue;
        case 5:
          if (tag != 42) {
            break;
          }

          message.user = reader.string();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;


@@ 303,6 325,8 @@ export const MessageC2SHello = {
      version: isSet(object.version) ? Number(object.version) : 0,
      requestedUsername: isSet(object.requestedUsername) ? String(object.requestedUsername) : "",
      nextState: isSet(object.nextState) ? stateFromJSON(object.nextState) : 0,
      token: isSet(object.token) ? String(object.token) : undefined,
      user: isSet(object.user) ? String(object.user) : undefined,
    };
  },



@@ 311,6 335,8 @@ export const MessageC2SHello = {
    message.version !== undefined && (obj.version = Math.round(message.version));
    message.requestedUsername !== undefined && (obj.requestedUsername = message.requestedUsername);
    message.nextState !== undefined && (obj.nextState = stateToJSON(message.nextState));
    message.token !== undefined && (obj.token = message.token);
    message.user !== undefined && (obj.user = message.user);
    return obj;
  },



@@ 323,6 349,8 @@ export const MessageC2SHello = {
    message.version = object.version ?? 0;
    message.requestedUsername = object.requestedUsername ?? "";
    message.nextState = object.nextState ?? 0;
    message.token = object.token ?? undefined;
    message.user = object.user ?? undefined;
    return message;
  },
};

M client/src/protocol/message_s2c.ts => client/src/protocol/message_s2c.ts +98 -0
@@ 1,6 1,7 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { GoodbyeReason, goodbyeReasonFromJSON, goodbyeReasonToJSON } from "./goodbye_reason";
import { Module } from "./module";
import { Planet } from "./planet";
import { Player } from "./player";
import { State, stateFromJSON, stateToJSON } from "./state";


@@ 239,6 240,43 @@ export function messageS2CPlanetData_packetInfoToJSON(object: MessageS2CPlanetDa
  }
}

export interface MessageS2CModulesUpdate {
  modules: Module[];
}

export enum MessageS2CModulesUpdate_packetInfo {
  unknown = 0,
  type = 11,
  UNRECOGNIZED = -1,
}

export function messageS2CModulesUpdate_packetInfoFromJSON(object: any): MessageS2CModulesUpdate_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CModulesUpdate_packetInfo.unknown;
    case 11:
    case "type":
      return MessageS2CModulesUpdate_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CModulesUpdate_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CModulesUpdate_packetInfoToJSON(object: MessageS2CModulesUpdate_packetInfo): string {
  switch (object) {
    case MessageS2CModulesUpdate_packetInfo.unknown:
      return "unknown";
    case MessageS2CModulesUpdate_packetInfo.type:
      return "type";
    case MessageS2CModulesUpdate_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

function createBaseMessageS2CHello(): MessageS2CHello {
  return { version: 0, givenUsername: "", nextState: 0 };
}


@@ 614,6 652,66 @@ export const MessageS2CPlanetData = {
  },
};

function createBaseMessageS2CModulesUpdate(): MessageS2CModulesUpdate {
  return { modules: [] };
}

export const MessageS2CModulesUpdate = {
  encode(message: MessageS2CModulesUpdate, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    for (const v of message.modules) {
      Module.encode(v!, writer.uint32(10).fork()).ldelim();
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CModulesUpdate {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CModulesUpdate();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 10) {
            break;
          }

          message.modules.push(Module.decode(reader, reader.uint32()));
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CModulesUpdate {
    return { modules: Array.isArray(object?.modules) ? object.modules.map((e: any) => Module.fromJSON(e)) : [] };
  },

  toJSON(message: MessageS2CModulesUpdate): unknown {
    const obj: any = {};
    if (message.modules) {
      obj.modules = message.modules.map((e) => e ? Module.toJSON(e) : undefined);
    } else {
      obj.modules = [];
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CModulesUpdate>, I>>(base?: I): MessageS2CModulesUpdate {
    return MessageS2CModulesUpdate.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CModulesUpdate>, I>>(object: I): MessageS2CModulesUpdate {
    const message = createBaseMessageS2CModulesUpdate();
    message.modules = object.modules?.map((e) => Module.fromPartial(e)) || [];
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T

A client/src/protocol/module.ts => client/src/protocol/module.ts +162 -0
@@ 0,0 1,162 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";

export const protobufPackage = "protocol.module";

export enum ModuleType {
  Cargo = 0,
  LandingThruster = 1,
  Hub = 2,
  UNRECOGNIZED = -1,
}

export function moduleTypeFromJSON(object: any): ModuleType {
  switch (object) {
    case 0:
    case "Cargo":
      return ModuleType.Cargo;
    case 1:
    case "LandingThruster":
      return ModuleType.LandingThruster;
    case 2:
    case "Hub":
      return ModuleType.Hub;
    case -1:
    case "UNRECOGNIZED":
    default:
      return ModuleType.UNRECOGNIZED;
  }
}

export function moduleTypeToJSON(object: ModuleType): string {
  switch (object) {
    case ModuleType.Cargo:
      return "Cargo";
    case ModuleType.LandingThruster:
      return "LandingThruster";
    case ModuleType.Hub:
      return "Hub";
    case ModuleType.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface Module {
  moduleType: ModuleType;
  rotation: number;
  x: number;
  y: number;
}

function createBaseModule(): Module {
  return { moduleType: 0, rotation: 0, x: 0, y: 0 };
}

export const Module = {
  encode(message: Module, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.moduleType !== 0) {
      writer.uint32(8).int32(message.moduleType);
    }
    if (message.rotation !== 0) {
      writer.uint32(21).float(message.rotation);
    }
    if (message.x !== 0) {
      writer.uint32(29).float(message.x);
    }
    if (message.y !== 0) {
      writer.uint32(37).float(message.y);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): Module {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseModule();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.moduleType = reader.int32() as any;
          continue;
        case 2:
          if (tag != 21) {
            break;
          }

          message.rotation = reader.float();
          continue;
        case 3:
          if (tag != 29) {
            break;
          }

          message.x = reader.float();
          continue;
        case 4:
          if (tag != 37) {
            break;
          }

          message.y = reader.float();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): Module {
    return {
      moduleType: isSet(object.moduleType) ? moduleTypeFromJSON(object.moduleType) : 0,
      rotation: isSet(object.rotation) ? Number(object.rotation) : 0,
      x: isSet(object.x) ? Number(object.x) : 0,
      y: isSet(object.y) ? Number(object.y) : 0,
    };
  },

  toJSON(message: Module): unknown {
    const obj: any = {};
    message.moduleType !== undefined && (obj.moduleType = moduleTypeToJSON(message.moduleType));
    message.rotation !== undefined && (obj.rotation = message.rotation);
    message.x !== undefined && (obj.x = message.x);
    message.y !== undefined && (obj.y = message.y);
    return obj;
  },

  create<I extends Exact<DeepPartial<Module>, I>>(base?: I): Module {
    return Module.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<Module>, I>>(object: I): Module {
    const message = createBaseModule();
    message.moduleType = object.moduleType ?? 0;
    message.rotation = object.rotation ?? 0;
    message.x = object.x ?? 0;
    message.y = object.y ?? 0;
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

M protocol/build.rs => protocol/build.rs +2 -1
@@ 9,5 9,6 @@ fn main() {
        .input("src/pbuf/player.proto")
        .input("src/pbuf/state.proto")
        .input("src/pbuf/goodbye_reason.proto")
        .input("src/pbuf/module.proto")
        .run_from_script();
}
\ No newline at end of file
}

M protocol/src/lib.rs => protocol/src/lib.rs +11 -4
@@ 1,12 1,12 @@
use std::error::Error;
use protobuf::{Enum, Message};
use crate::message_c2s::{MessageC2SAuthenticateAndBeamOut, MessageC2SChat, MessageC2SGoodbye, MessageC2SHello, MessageC2SInput, MessageC2SPing};
use crate::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong};
use crate::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong, MessageS2CModulesUpdate};
use crate::planet::PlanetType;
use crate::starkingdoms_protocol::PacketWrapper;
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));

pub const PROTOCOL_VERSION: u32 = 2;
pub const PROTOCOL_VERSION: u32 = 3;

pub mod api;



@@ 27,7 27,8 @@ pub enum MessageS2C {
    Chat(MessageS2CChat),
    Pong(MessageS2CPong),
    PlayersUpdate(MessageS2CPlayersUpdate),
    PlanetData(MessageS2CPlanetData)
    PlanetData(MessageS2CPlanetData),
    ModulesUpdate(MessageS2CModulesUpdate),
}

impl TryFrom<&[u8]> for MessageC2S {


@@ 122,6 123,9 @@ impl TryFrom<&[u8]> for MessageS2C {
            _id if _id == message_s2c::message_s2cplanet_data::Packet_info::type_.value() as i64 => {
                MessageS2C::PlanetData(MessageS2CPlanetData::parse_from_bytes(&pkt.packet_data)?)
            },
            _id if _id == message_s2c::message_s2cmodules_update::Packet_info::type_.value() as i64 => {
                MessageS2C::ModulesUpdate(MessageS2CModulesUpdate::parse_from_bytes(&pkt.packet_data)?)
            },
            _ => { return Err("Not a S2C packet".into()); }
        };



@@ 152,6 156,9 @@ impl TryInto<Vec<u8>> for MessageS2C {
            MessageS2C::PlanetData(p) => {
                (message_s2c::message_s2cplanet_data::Packet_info::type_.value(), p.write_to_bytes()?)
            }
            MessageS2C::ModulesUpdate(p) => {
                (message_s2c::message_s2cmodules_update::Packet_info::type_.value(), p.write_to_bytes()?)
            }
        };

        let pkt = PacketWrapper {


@@ 171,4 178,4 @@ impl planet::PlanetType {
            PlanetType::Moon => "moon".to_string()
        }
    }
}
\ No newline at end of file
}

M protocol/src/pbuf/message_s2c.proto => protocol/src/pbuf/message_s2c.proto +8 -1
@@ 5,6 5,7 @@ import "state.proto";
import "goodbye_reason.proto";
import "player.proto";
import "planet.proto";
import "module.proto";

message MessageS2CHello {
  enum packet_info { unknown = 0; type = 0x05; }


@@ 41,4 42,10 @@ message MessageS2CPlanetData {
  enum packet_info { unknown = 0; type = 0x0a; }

  repeated protocol.planet.Planet planets = 1;  // List of all planets on the server
}
\ No newline at end of file
}

message MessageS2CModulesUpdate {
  enum packet_info { unknown = 0; type = 0x0b; }

  repeated protocol.module.Module modules = 1;
}

A protocol/src/pbuf/module.proto => protocol/src/pbuf/module.proto +15 -0
@@ 0,0 1,15 @@
syntax = "proto3";
package protocol.module;

message Module {
    ModuleType module_type = 1;
    float rotation = 2;
    float x = 3;
    float y = 4;
}

enum ModuleType {
    Cargo = 0;
    LandingThruster = 1;
    Hub = 2;
}

M server/src/entity.rs => server/src/entity.rs +21 -2
@@ 3,7 3,7 @@ use std::{sync::atomic::AtomicU32, collections::HashMap, net::SocketAddr};
use nalgebra::Vector2;
use starkingdoms_protocol::planet::PlanetType;

use crate::{planet::Planet, SCALE, manager::{ClientHandlerMessage, Player}};
use crate::{planet::Planet, SCALE, manager::{ClientHandlerMessage, Player, Module}};

pub type EntityId = u32;
pub type Entities = HashMap<EntityId, Entity>;


@@ 11,7 11,7 @@ static mut ENTITY_ID_COUNT: AtomicU32 = AtomicU32::new(0);
pub fn get_entity_id() -> EntityId {
    let last_entity_id = unsafe { &ENTITY_ID_COUNT };
    let id = last_entity_id.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
    if id > 2_147_483_600 { panic!("No remaining entity ids") };
    if id > 4_147_483_600 { panic!("No remaining entity ids") };
    id
}



@@ 78,6 78,24 @@ impl EntityHandler {
        }
        Some(players[0].clone().1)
    }
    pub fn get_modules(&self) -> Vec<Module> {
        let mut modules = Vec::new();
        for entity in self.entities.values() {
            if let Entity::Module(module) = entity {
                modules.push(module.clone());
            }
        }
        modules
    }
    pub fn get_module_count(&self) -> u32 {
        let mut module_count = 0;
        for entity in self.entities.values() {
            if let Entity::Module(_module) = entity {
                module_count += 1;
            }
        }
        module_count
    }

    pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
        let mut direction = Vector2::zeros();


@@ 114,4 132,5 @@ impl EntityHandler {
pub enum Entity {
    Player(Player),
    Planet(Planet),
    Module(Module),
}

M server/src/handler.rs => server/src/handler.rs +10 -2
@@ 11,7 11,7 @@ use rand::Rng;
use rapier2d_f64::prelude::{RigidBodyBuilder, RigidBodyType, ColliderBuilder, MassProperties, Collider};
use tungstenite::Message;
use starkingdoms_protocol::goodbye_reason::GoodbyeReason;
use starkingdoms_protocol::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong};
use starkingdoms_protocol::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong, MessageS2CModulesUpdate};
use starkingdoms_protocol::{MessageS2C, MessageC2S, PROTOCOL_VERSION};
use starkingdoms_protocol::state::State;
use crate::entity::{EntityHandler, get_entity_id, Entity};


@@ 20,7 20,6 @@ use crate::{send, recv, SCALE};
use async_std::{sync::RwLock, channel::Receiver};
use async_std::net::TcpStream;
use async_tungstenite::WebSocketStream;
use starkingdoms_protocol::api::APISavedPlayerData;
use crate::api::{load_player_data_from_api, save_player_data_to_api};

pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandler>>, data: Arc<RwLock<PhysicsData>>,


@@ 63,6 62,15 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
                        send!(client_tx, msg).await?;
                    }
                }
                ClientHandlerMessage::ModulesUpdate { modules } => {
                    if matches!(state, State::Play) {
                        let msg = MessageS2C::ModulesUpdate(MessageS2CModulesUpdate {
                            modules,
                            special_fields: Default::default(),
                        }).try_into()?;
                        send!(client_tx, msg).await?;
                    }
                }
            }
        } else {
            info!("channel closed, shutting down");

M server/src/manager.rs => server/src/manager.rs +8 -0
@@ 6,6 6,7 @@ use rapier2d_f64::prelude::{IntegrationParameters, PhysicsPipeline, IslandManage
use async_std::sync::RwLock;
use async_std::channel::Sender;
use starkingdoms_protocol::api::APISavedPlayerData;
use starkingdoms_protocol::module::ModuleType;

#[derive(Clone)]
pub struct ClientManager {


@@ 31,6 32,12 @@ impl Player {
    }
}

#[derive(Clone)]
pub struct Module {
    pub handle: RigidBodyHandle,
    pub module_type: ModuleType,
}

#[derive(Default, Clone)]
pub struct PlayerInput {
    pub up: bool,


@@ 81,4 88,5 @@ pub enum ClientHandlerMessage {
    ChatMessage { from: String, message: String },
    PlayersUpdate { players: Vec<starkingdoms_protocol::player::Player> },
    PlanetData { planets: Vec<starkingdoms_protocol::planet::Planet> },
    ModulesUpdate { modules: Vec<starkingdoms_protocol::module::Module> },
}

M server/src/timer.rs => server/src/timer.rs +69 -7
@@ 1,25 1,29 @@
use std::{time::Duration, sync::Arc};
use std::{time::Duration, sync::Arc, f64::consts::PI};
use log::{debug, warn};
use nalgebra::{vector, point};
use rapier2d_f64::prelude::{PhysicsPipeline};
use rand::Rng;
use rapier2d_f64::prelude::{PhysicsPipeline, ColliderBuilder, RigidBodyBuilder};
use async_std::sync::RwLock;
use async_std::task::sleep;
use starkingdoms_protocol::{player::Player, planet::PlanetType};
use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData}, SCALE, planet::{Planets, Planet}, entity::{Entities, Entity, EntityHandler}};
use starkingdoms_protocol::{player::Player, planet::PlanetType, module::ModuleType};
use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData, Module}, SCALE, planet::{Planets, Planet}, entity::{Entities, Entity, EntityHandler, get_entity_id}};
use crate::orbit::constants::{EARTH_MASS, GAME_ORBITS_ENABLED, MOON_APOAPSIS, MOON_MASS, MOON_ORBIT_TIME, MOON_PERIAPSIS};
use crate::orbit::orbit::{calculate_point_on_orbit, calculate_vector_of_orbit, calculate_world_position_of_orbit};

pub const ROTATIONAL_FORCE: f64 = 100.0;
pub const LATERAL_FORCE: f64 = 100.0;
pub const MODULE_SPAWN: f64 = 1000.0;
pub const MODULE_MAX: u32 = 10;

pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>, entities: Arc<RwLock<EntityHandler>>) {
pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<PhysicsData>>, entities: Arc<RwLock<EntityHandler>>) {
    let mut pipeline = PhysicsPipeline::new();

    let mut time = 0.0;
    let mut module_timer = 0.0;
    let planet_ids;

    {
        let mut data_handle = physics_data.write().await;
        let mut data_handle = physics_data_orig.write().await;

        let mut rigid_body_set = data_handle.rigid_body_set.clone();
        let mut collider_set = data_handle.collider_set.clone();


@@ 33,8 37,9 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
    loop {
        sleep(Duration::from_millis(5)).await;
        time += 5.0 / 1000.0; // 5ms, time is in seconds
        module_timer += 5.0 / 1000.0;

        let mut physics_data = physics_data.write().await;
        let mut physics_data = physics_data_orig.write().await;

        // update orbits (but dont, actually, yet)
        // DO NOT SIMPLIFY EXPRESSION


@@ 61,6 66,45 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
        let mut protocol_players = vec![];

        {
            if module_timer > 1.0 && entities.read().await.get_module_count() < MODULE_MAX {
                debug!("module spawn");
                module_timer = 0.;

                let mut rigid_body_set = physics_data.rigid_body_set.clone();
                let mut collider_set = physics_data.collider_set.clone();

                let module_collider = ColliderBuilder::cuboid(25. / SCALE, 25. / SCALE);
                let angle: f64 = {
                    let mut rng = rand::thread_rng();
                    rng.gen::<f64>() * PI * 2.
                };
                let module_body = RigidBodyBuilder::dynamic()
                    .translation(vector![angle.cos() * 2050. / SCALE, angle.sin() * 2050.0/SCALE])
                    .build();
                let module_handler = rigid_body_set.insert(module_body);
                collider_set.insert_with_parent(module_collider, module_handler, &mut rigid_body_set);

                physics_data.rigid_body_set = rigid_body_set;
                physics_data.collider_set = collider_set;

                let module = Module {
                    handle: module_handler,
                    module_type: ModuleType::Cargo,
                };
                entities.write().await.entities.insert(get_entity_id(), Entity::Module(module));
            }
            for module in entities.read().await.get_modules().iter() {
                let module_handle = module.handle;
                let module_body = physics_data.rigid_body_set.get_mut(module_handle).unwrap();
                module_body.reset_forces(true);
                module_body.reset_torques(true);
                let planets = entities.read().await;
                let grav_force = planets.gravity((module_body.translation().x, module_body.translation().y), module_body.mass());
                module_body.apply_impulse(vector![grav_force.0, grav_force.1], true);
            }
        }

        {
            for (player_id, player) in entities.read().await.get_players().iter() {
                let player_handle = player.handle;
                let player_body = physics_data.rigid_body_set.get_mut(player_handle).unwrap();


@@ 179,6 223,24 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
                            warn!("unable to send position packet: {}", e);
                        }
                    };
                    let modules = entities.read().await.get_modules();
                    let protocol_modules: Vec<starkingdoms_protocol::module::Module> = modules.iter()
                        .map(|module| {
                            let body = physics_data.rigid_body_set.get(module.handle).unwrap();
                            return starkingdoms_protocol::module::Module {
                                module_type: module.module_type.into(),
                                rotation: body.rotation().angle() as f32,
                                x: (body.translation().x * SCALE) as f32,
                                y: (body.translation().y * SCALE) as f32,
                                special_fields: Default::default(),
                            };
                        }).collect();
                    match client_thread.tx.send(ClientHandlerMessage::ModulesUpdate { modules: protocol_modules.clone() }).await {
                        Ok(_) => (),
                        Err(e) => {
                            warn!("unable to send module position packet: {}", e);
                        }
                    };

                    let world = entities.read().await;
                    let planet_data = world.to_protocol();