M client/src/gateway.ts => client/src/gateway.ts +5 -0
@@ 14,6 14,8 @@ import {
MessageS2CGoodbye_packetInfo,
MessageS2CHello,
MessageS2CHello_packetInfo,
+ MessageS2CModulesUpdate,
+ MessageS2CModulesUpdate_packetInfo,
MessageS2CPlanetData, MessageS2CPlanetData_packetInfo,
MessageS2CPlayersUpdate,
MessageS2CPlayersUpdate_packetInfo,
@@ 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 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();