M Cargo.toml => Cargo.toml +4 -1
@@ 2,4 2,7 @@
members = [
"server",
"protocol"
-]>
\ No newline at end of file
+]
+
+[profile.dev.package.rapier2d-f64]
+opt-level = 3<
\ No newline at end of file
M assets/dist/spritesheet-125.json => assets/dist/spritesheet-125.json +5 -5
@@ 18,7 18,7 @@
"pivot": { "x": 32, "y": 32 },
"9slicedFrame": { "x": 0, "y": 0, "w": 64, "h": 64 }
},
- "hearty.png": {
+ "autoplr_error.png": {
"frame": { "x": 0, "y": 320, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
@@ 27,7 27,7 @@
"pivot": { "x": 32, "y": 32 },
"9slicedFrame": { "x": 0, "y": 0, "w": 64, "h": 64 }
},
- "autoplr_error.png": {
+ "hearty.png": {
"frame": { "x": 0, "y": 384, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
@@ 90,7 90,7 @@
"pivot": { "x": 32, "y": 32 },
"9slicedFrame": { "x": 0, "y": 0, "w": 64, "h": 64 }
},
- "powerhub_on.png": {
+ "hub_on.png": {
"frame": { "x": 0, "y": 832, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
@@ 99,7 99,7 @@
"pivot": { "x": 32, "y": 32 },
"9slicedFrame": { "x": 0, "y": 0, "w": 64, "h": 64 }
},
- "hub_on.png": {
+ "autoplr_on.png": {
"frame": { "x": 0, "y": 896, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
@@ 108,7 108,7 @@
"pivot": { "x": 32, "y": 32 },
"9slicedFrame": { "x": 0, "y": 0, "w": 64, "h": 64 }
},
- "autoplr_on.png": {
+ "powerhub_on.png": {
"frame": { "x": 0, "y": 960, "w": 64, "h": 64 },
"rotated": false,
"trimmed": false,
M assets/dist/spritesheet-125.png => assets/dist/spritesheet-125.png +0 -0
M assets/dist/spritesheet-375.json => assets/dist/spritesheet-375.json +6 -6
@@ 18,7 18,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "hearty.png": {
+ "autoplr_error.png": {
"frame": { "x": 0, "y": 960, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
@@ 27,7 27,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "autoplr_error.png": {
+ "hearty.png": {
"frame": { "x": 0, "y": 1152, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
@@ 90,7 90,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "powerhub_on.png": {
+ "autoplr_on.png": {
"frame": { "x": 0, "y": 2496, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
@@ 108,7 108,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "autoplr_on.png": {
+ "powerhub_on.png": {
"frame": { "x": 0, "y": 2880, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
@@ 162,7 162,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "powerhub_off.png": {
+ "hub_off.png": {
"frame": { "x": 768, "y": 0, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
@@ 171,7 171,7 @@
"pivot": { "x": 96, "y": 96 },
"9slicedFrame": { "x": 0, "y": 0, "w": 192, "h": 192 }
},
- "hub_off.png": {
+ "powerhub_off.png": {
"frame": { "x": 960, "y": 0, "w": 192, "h": 192 },
"rotated": false,
"trimmed": false,
M assets/dist/spritesheet-375.png => assets/dist/spritesheet-375.png +0 -0
M assets/dist/spritesheet-full.json => assets/dist/spritesheet-full.json +7 -7
@@ 18,7 18,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "hearty.png": {
+ "autoplr_error.png": {
"frame": { "x": 0, "y": 2560, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 27,7 27,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "autoplr_error.png": {
+ "hearty.png": {
"frame": { "x": 0, "y": 3072, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 90,7 90,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "powerhub_on.png": {
+ "hub_on.png": {
"frame": { "x": 512, "y": 2560, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 99,7 99,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "hub_on.png": {
+ "autoplr_on.png": {
"frame": { "x": 512, "y": 3072, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 108,7 108,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "autoplr_on.png": {
+ "powerhub_on.png": {
"frame": { "x": 512, "y": 3584, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 162,7 162,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "powerhub_off.png": {
+ "hub_off.png": {
"frame": { "x": 1024, "y": 2560, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
@@ 171,7 171,7 @@
"pivot": { "x": 256, "y": 256 },
"9slicedFrame": { "x": 0, "y": 0, "w": 512, "h": 512 }
},
- "hub_off.png": {
+ "powerhub_off.png": {
"frame": { "x": 1024, "y": 3072, "w": 512, "h": 512 },
"rotated": false,
"trimmed": false,
M assets/dist/spritesheet-full.png => assets/dist/spritesheet-full.png +0 -0
M client/src/index.ts => client/src/index.ts +59 -2
@@ 5,6 5,8 @@ import {Logger, logSetup} from "./logger";
import {gateway_connect, GatewayClient} from "./gateway";
import {Player} from "./protocol/player";
import {Planet, PlanetType} from "./protocol/planet";
+import {MessageC2SInput, MessageC2SInput_packetInfo} from "./protocol/message_c2s";
+import {encode} from "./serde";
logSetup();
const logger = new Logger("client");
@@ 17,8 19,17 @@ export interface GlobalData {
canvas: HTMLCanvasElement,
spritesheet_img: HTMLImageElement | null,
spritesheet: object | null,
- context: CanvasRenderingContext2D
+ context: CanvasRenderingContext2D,
+ keys: Keys
}
+
+export interface Keys {
+ up: boolean,
+ left: boolean,
+ down: boolean,
+ right: boolean
+}
+
export const global: GlobalData = {
client: null,
players: [],
@@ 27,7 38,13 @@ export const global: GlobalData = {
canvas: <HTMLCanvasElement>document.getElementById("canvas"),
spritesheet_img: null,
spritesheet: null,
- context: <CanvasRenderingContext2D>(<HTMLCanvasElement>document.getElementById("canvas")).getContext("2d")
+ context: <CanvasRenderingContext2D>(<HTMLCanvasElement>document.getElementById("canvas")).getContext("2d"),
+ keys: {
+ up: false,
+ down: false,
+ left: false,
+ right: false
+ }
}
async function client_main(server: string, username: string, texture_quality: string) {
@@ 72,6 89,46 @@ async function client_main(server: string, username: string, texture_quality: st
global.canvas.style.setProperty("background-image", `url("/assets/final/${texture_quality}/starfield.png")`);
+ document.onkeydown = (e) => {
+ if (e.code == "ArrowLeft") { // arrow-left
+ global.keys.left = true;
+ } else if (e.code == "ArrowRight") { // arrow-right
+ global.keys.right = true;
+ } else if (e.code == "ArrowUp") { // arrow-up
+ global.keys.up = true;
+ } else if (e.code == "ArrowDown") { // arrow-down
+ global.keys.down = true;
+ }
+
+ let msg = MessageC2SInput.encode({
+ upPressed: global.keys.up,
+ downPressed: global.keys.down,
+ leftPressed: global.keys.left,
+ rightPressed: global.keys.right
+ }).finish();
+
+ global.client?.socket.send(encode(MessageC2SInput_packetInfo.type, msg));
+ }
+ document.onkeyup = (e) => {
+ if (e.code == "ArrowLeft") { // arrow-left
+ global.keys.left = false;
+ } else if (e.code == "ArrowRight") { // arrow-right
+ global.keys.right = false;
+ } else if (e.code == "ArrowUp") { // arrow-up
+ global.keys.up = false;
+ } else if (e.code == "ArrowDown") { // arrow-down
+ global.keys.down = false;
+ }
+
+ let msg = MessageC2SInput.encode({
+ upPressed: global.keys.up,
+ downPressed: global.keys.down,
+ leftPressed: global.keys.left,
+ rightPressed: global.keys.right
+ }).finish();
+ global.client?.socket.send(encode(MessageC2SInput_packetInfo.type, msg));
+ }
+
let last_time = performance.now();
let render = (now_time: DOMHighResTimeStamp) => {
const delta_ms = now_time - last_time;
M client/src/protocol/message_c2s.ts => client/src/protocol/message_c2s.ts +137 -0
@@ 159,6 159,46 @@ export function messageC2SPing_packetInfoToJSON(object: MessageC2SPing_packetInf
}
}
+export interface MessageC2SInput {
+ upPressed: boolean;
+ downPressed: boolean;
+ leftPressed: boolean;
+ rightPressed: boolean;
+}
+
+export enum MessageC2SInput_packetInfo {
+ unknown = 0,
+ type = 11,
+ UNRECOGNIZED = -1,
+}
+
+export function messageC2SInput_packetInfoFromJSON(object: any): MessageC2SInput_packetInfo {
+ switch (object) {
+ case 0:
+ case "unknown":
+ return MessageC2SInput_packetInfo.unknown;
+ case 11:
+ case "type":
+ return MessageC2SInput_packetInfo.type;
+ case -1:
+ case "UNRECOGNIZED":
+ default:
+ return MessageC2SInput_packetInfo.UNRECOGNIZED;
+ }
+}
+
+export function messageC2SInput_packetInfoToJSON(object: MessageC2SInput_packetInfo): string {
+ switch (object) {
+ case MessageC2SInput_packetInfo.unknown:
+ return "unknown";
+ case MessageC2SInput_packetInfo.type:
+ return "type";
+ case MessageC2SInput_packetInfo.UNRECOGNIZED:
+ default:
+ return "UNRECOGNIZED";
+ }
+}
+
function createBaseMessageC2SHello(): MessageC2SHello {
return { version: 0, requestedUsername: "", nextState: 0 };
}
@@ 399,6 439,103 @@ export const MessageC2SPing = {
},
};
+function createBaseMessageC2SInput(): MessageC2SInput {
+ return { upPressed: false, downPressed: false, leftPressed: false, rightPressed: false };
+}
+
+export const MessageC2SInput = {
+ encode(message: MessageC2SInput, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
+ if (message.upPressed === true) {
+ writer.uint32(8).bool(message.upPressed);
+ }
+ if (message.downPressed === true) {
+ writer.uint32(16).bool(message.downPressed);
+ }
+ if (message.leftPressed === true) {
+ writer.uint32(24).bool(message.leftPressed);
+ }
+ if (message.rightPressed === true) {
+ writer.uint32(32).bool(message.rightPressed);
+ }
+ return writer;
+ },
+
+ decode(input: _m0.Reader | Uint8Array, length?: number): MessageC2SInput {
+ const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
+ let end = length === undefined ? reader.len : reader.pos + length;
+ const message = createBaseMessageC2SInput();
+ while (reader.pos < end) {
+ const tag = reader.uint32();
+ switch (tag >>> 3) {
+ case 1:
+ if (tag != 8) {
+ break;
+ }
+
+ message.upPressed = reader.bool();
+ continue;
+ case 2:
+ if (tag != 16) {
+ break;
+ }
+
+ message.downPressed = reader.bool();
+ continue;
+ case 3:
+ if (tag != 24) {
+ break;
+ }
+
+ message.leftPressed = reader.bool();
+ continue;
+ case 4:
+ if (tag != 32) {
+ break;
+ }
+
+ message.rightPressed = reader.bool();
+ continue;
+ }
+ if ((tag & 7) == 4 || tag == 0) {
+ break;
+ }
+ reader.skipType(tag & 7);
+ }
+ return message;
+ },
+
+ fromJSON(object: any): MessageC2SInput {
+ return {
+ upPressed: isSet(object.upPressed) ? Boolean(object.upPressed) : false,
+ downPressed: isSet(object.downPressed) ? Boolean(object.downPressed) : false,
+ leftPressed: isSet(object.leftPressed) ? Boolean(object.leftPressed) : false,
+ rightPressed: isSet(object.rightPressed) ? Boolean(object.rightPressed) : false,
+ };
+ },
+
+ toJSON(message: MessageC2SInput): unknown {
+ const obj: any = {};
+ message.upPressed !== undefined && (obj.upPressed = message.upPressed);
+ message.downPressed !== undefined && (obj.downPressed = message.downPressed);
+ message.leftPressed !== undefined && (obj.leftPressed = message.leftPressed);
+ message.rightPressed !== undefined && (obj.rightPressed = message.rightPressed);
+ return obj;
+ },
+
+ create<I extends Exact<DeepPartial<MessageC2SInput>, I>>(base?: I): MessageC2SInput {
+ return MessageC2SInput.fromPartial(base ?? {});
+ },
+
+ fromPartial<I extends Exact<DeepPartial<MessageC2SInput>, I>>(object: I): MessageC2SInput {
+ const message = createBaseMessageC2SInput();
+ message.upPressed = object.upPressed ?? false;
+ message.downPressed = object.downPressed ?? false;
+ message.leftPressed = object.leftPressed ?? false;
+ message.rightPressed = object.rightPressed ?? false;
+ return message;
+ },
+};
+
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
M protocol/src/lib.rs => protocol/src/lib.rs +10 -3
@@ 1,6 1,6 @@
use std::error::Error;
use protobuf::{Enum, Message};
-use crate::message_c2s::{MessageC2SChat, MessageC2SGoodbye, MessageC2SHello, MessageC2SPing};
+use crate::message_c2s::{MessageC2SChat, MessageC2SGoodbye, MessageC2SHello, MessageC2SInput, MessageC2SPing};
use crate::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong};
use crate::planet::PlanetType;
use crate::starkingdoms_protocol::PacketWrapper;
@@ 13,7 13,8 @@ pub enum MessageC2S {
Hello(MessageC2SHello),
Goodbye(MessageC2SGoodbye),
Chat(MessageC2SChat),
- Ping(MessageC2SPing)
+ Ping(MessageC2SPing),
+ Input(MessageC2SInput)
}
#[derive(Debug)]
@@ 44,8 45,11 @@ impl TryFrom<&[u8]> for MessageC2S {
},
_id if _id == message_c2s::message_c2sping::Packet_info::type_.value() as i64 => {
MessageC2S::Ping(MessageC2SPing::parse_from_bytes(&pkt.packet_data)?)
+ },
+ _id if _id == message_c2s::message_c2sinput::Packet_info::type_.value() as i64 => {
+ MessageC2S::Input(MessageC2SInput::parse_from_bytes(&pkt.packet_data)?)
}
- _ => { return Err("Not a C2S packet".into()); }
+ _id => { return Err(format!("Unrecognized C2S packet {}", _id).into()); }
};
Ok(deser_pkt)
@@ 69,6 73,9 @@ impl TryInto<Vec<u8>> for MessageC2S {
MessageC2S::Ping(p) => {
(message_c2s::message_c2sping::Packet_info::type_.value(), p.write_to_bytes()?)
}
+ MessageC2S::Input(p) => {
+ (message_c2s::message_c2sping::Packet_info::type_.value(), p.write_to_bytes()?)
+ }
};
let pkt = PacketWrapper {
M protocol/src/pbuf/message_c2s.proto => protocol/src/pbuf/message_c2s.proto +9 -0
@@ 26,4 26,13 @@ message MessageC2SChat {
message MessageC2SPing {
enum packet_info { unknown = 0; type = 0x04; }
+}
+
+message MessageC2SInput {
+ enum packet_info { unknown = 0; type = 0x0b; }
+
+ bool up_pressed = 1;
+ bool down_pressed = 2;
+ bool left_pressed = 3;
+ bool right_pressed = 4;
}=
\ No newline at end of file
M server/Cargo.toml => server/Cargo.toml +1 -1
@@ 25,4 25,4 @@ rapier2d-f64 = { version = "0.17.2", features = [ "simd-stable" ] }
nalgebra = "0.32.2"
[build-dependencies]
-cargo_metadata = "0.15"
+cargo_metadata = "0.15"<
\ No newline at end of file
M server/src/handler.rs => server/src/handler.rs +11 -2
@@ 5,7 5,7 @@ use std::time::{Duration, SystemTime};
use futures::stream::{SplitSink, SplitStream};
use futures::{FutureExt, SinkExt, StreamExt};
use hyper::upgrade::Upgraded;
-use log::{error, info};
+use log::{debug, error, info};
use nalgebra::vector;
use rapier2d_f64::prelude::{RigidBodyBuilder, RigidBodyType, ColliderBuilder};
use tokio::sync::RwLock;
@@ 148,7 148,7 @@ pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, r
data_handle.rigid_body_set = rigid_body_set;
data_handle.collider_set = collider_set;
- mgr.players.write().await.insert(remote_addr, Player { handle: player_handle });
+ mgr.players.write().await.insert(remote_addr, Player { handle: player_handle, input: Default::default() });
}
},
MessageC2S::Goodbye(pkt) => {
@@ 199,6 199,15 @@ pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, r
}).try_into()?;
send!(client_tx, msg).await?;
ping_timeout = SystemTime::now() + Duration::from_secs(10);
+ },
+ MessageC2S::Input(p) => {
+ let mut players = mgr.players.write().await;
+ let me = players.get_mut(&remote_addr).expect("player disconnected but continued to send packets");
+ me.input.up = p.up_pressed;
+ me.input.down = p.down_pressed;
+ me.input.left = p.left_pressed;
+ me.input.right = p.right_pressed;
+ debug!("{} {} {} {}", me.input.up, me.input.down, me.input.left, me.input.right);
}
}
}
M server/src/main.rs => server/src/main.rs +1 -1
@@ 50,7 50,7 @@ async fn handle_request(mut request: Request<Body>, remote_addr: SocketAddr, mgr
//pass the upgraded object
//as the base layer stream of the Websocket
upgraded,
- tokio_tungstenite::tungstenite::protocol::Role::Server,
+ tungstenite::protocol::Role::Server,
None,
).await;
M server/src/manager.rs => server/src/manager.rs +10 -1
@@ 15,7 15,16 @@ pub struct ClientManager {
#[derive(Default)]
pub struct Player {
- pub handle: RigidBodyHandle
+ pub handle: RigidBodyHandle,
+ pub input: PlayerInput
+}
+
+#[derive(Default)]
+pub struct PlayerInput {
+ pub up: bool,
+ pub left: bool,
+ pub right: bool,
+ pub down: bool
}
#[derive(Clone)]
M server/src/timer.rs => server/src/timer.rs +34 -3
@@ 1,11 1,14 @@
use std::{time::Duration, sync::Arc};
-use log::{error};
+use log::{debug, error};
use nalgebra::vector;
use rapier2d_f64::prelude::{PhysicsPipeline};
use tokio::{time::sleep, sync::RwLock};
use starkingdoms_protocol::player::Player;
use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData}, SCALE, planet::Planets};
+pub const ROTATIONAL_FORCE: f64 = 100.0;
+pub const LATERAL_FORCE: f64 = 100.0;
+
pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>, world_data: Arc<RwLock<Planets>>) {
let mut pipeline = PhysicsPipeline::new();
loop {
@@ 24,8 27,36 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
let grav_force = planets.gravity((player_body.translation().x, player_body.translation().y), player_body.mass());
player_body.add_force(vector![grav_force.0, grav_force.1], true);
+ let mut torque = 0.0;
+
+ if player.input.right {
+ torque += ROTATIONAL_FORCE;
+ }
+ if player.input.left {
+ torque -= ROTATIONAL_FORCE;
+ }
+
+ player_body.add_torque(torque, true);
+
+ let mut lateral = vector![0.0, 0.0];
+
+ if player.input.up {
+ lateral -= vector![0.0, LATERAL_FORCE];
+ }
+ if player.input.down {
+ lateral += vector![0.0, LATERAL_FORCE];
+ }
+
+ let rotation = player_body.rotation().clone().angle();
+
+ let lateral_rotated = vector![
+ lateral.x * rotation.cos() - lateral.y * rotation.sin(),
+ lateral.x * rotation.sin() + lateral.y * rotation.cos()
+ ];
+
+ player_body.add_force(lateral_rotated, true);
+
let translation = player_body.translation();
- let rotation = player_body.rotation();
let username;
{
@@ 35,7 66,7 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
// TODO: Figure out how to adjust codegen to use f64
protocol_players.push(Player {
- rotation: rotation.angle() as f32,
+ rotation: rotation as f32,
x: (translation.x * SCALE) as f32,
y: (translation.y * SCALE) as f32,
username,