build client updateeeee

This commit is contained in:
MeexReay 2024-12-22 01:36:43 +03:00
parent b57e8938d2
commit 16f2656645
7 changed files with 7 additions and 1347 deletions

View file

@ -7,3 +7,9 @@ cat dest/network.js >> dest/script.js
cat dest/player.js >> dest/script.js
cat dest/core.js >> dest/script.js
terser dest/script.js -o dest/script.min.js --compress --mangle
rm dest/script.js
rm dest/main.js
rm dest/block.js
rm dest/network.js
rm dest/player.js
rm dest/core.js

View file

@ -1,112 +0,0 @@
class Block {
constructor(x, y, color, collides, type) {
this.x = x;
this.y = y;
this.color = color;
this.collides = collides;
this.type = type;
}
render() {
let rect = this.translate_to_camera();
if (this.is_need_render(rect)) {
ctx.fillStyle = this.color;
ctx.fillRect(...rect);
}
}
is_need_render(rect) {
return rect[0] + rect[2] > 0 || rect[1] + rect[3] > 0 || rect[0] < width || rect[1] < height;
}
translate_to_camera() {
let size = camera.size * 16;
return [
this.x * size - size / 2 + (width / 2 - camera.x * size),
height - (this.y + 1) * size + size / 2 - (height / 2 - camera.y * size),
size,
size
];
}
tick() {
}
renderTick() {
}
on_collide(player, x, y) {
if (x != 0)
player.velocity_x = this.x + x - player.x;
if (y != 0)
player.velocity_y = this.y + y - player.y;
}
renderText() {
}
}
class Player extends Block {
constructor(x, y, name, color, velocity_x, velocity_y) {
super(x, y, color, true, null);
this.velocity_x = velocity_x;
this.velocity_y = velocity_y;
this.name = name;
}
reset() {
this.on_ground = false;
}
on_collide(player, x, y) {
super.on_collide(player, x, y);
}
tick(collide = true) {
this.x = Math.round(this.x * 100) / 100;
this.y = Math.round(this.y * 100) / 100;
this.velocity_x = Math.round(this.velocity_x * 100) / 100;
this.velocity_y = Math.round(this.velocity_y * 100) / 100;
if (collide)
this.collide();
}
collide() {
this.on_ground = false;
for (const block of blocks) {
if (!block.collides)
continue;
let collide_x = 0;
let collide_y = 0;
if (this.x > block.x - 1 && this.x < block.x + 1) {
if (this.y > block.y && this.y + this.velocity_y - 1 < block.y) {
this.on_ground = true;
collide_y = 1;
}
if (this.y < block.y && this.y + this.velocity_y > block.y - 1)
collide_y = -1;
}
if (this.y > block.y - 1 && this.y < block.y + 1) {
if (this.x > block.x && this.x + this.velocity_x - 1 < block.x)
collide_x = 1;
if (this.x < block.x && this.x + this.velocity_x > block.x - 1)
collide_x = -1;
}
block.on_collide(this, collide_x, collide_y);
}
}
renderTick() {
this.velocity_x *= 0.5;
this.velocity_y *= 0.5;
this.x += this.velocity_x;
this.y += this.velocity_y;
}
renderText() {
super.renderText();
let rect = this.translate_to_camera();
if (this.is_need_render(rect)) {
ctx.fillStyle = "#ddd";
ctx.font = "15px monospace";
let width = ctx.measureText(this.name).width;
ctx.fillText(this.name, rect[0] + rect[2] / 2 - width / 2, rect[1] - 5);
}
}
teleport(x, y) {
this.velocity_x = x - this.x;
this.velocity_y = y - this.y;
}
forceTeleport(x, y) {
this.x = x;
this.y = y;
this.velocity_x = 0;
this.velocity_y = 0;
}
}

View file

@ -1,90 +0,0 @@
var ticksAlive = 0;
var debugMode = false;
var camera = {
x: 0.0,
y: 0.0,
size: 1.5
};
var chatOpened = false;
var chatMessages = [];
var chatTyping = "";
var player = new MainPlayer();
player.register();
var blocks = [];
const allowed_key_to_send = [
"KeyR", "KeyW", "KeyE", "KeyQ", "KeyS",
"Numpad1", "Numpad2", "Numpad3", "Numpad4", "Numpad5",
"Numpad6", "Numpad7", "Numpad8", "Numpad9", "Numpad0",
"ShiftLeft", "ControlLeft", "Enter",
"F1", "F2", "KeyZ", "KeyX", "KeyC"
];
function connectServer(address, name) {
player.closeConnection();
player.onConnect(name);
try {
let conn = new Connection(address, player.onPacket, (e) => {
player.conn = null;
setServerError(e == null ? "Connection closed due to error" : e);
resetWorld();
});
conn.send(new JoinPacket(name));
}
catch (exception) {
setServerError(exception);
}
}
function resetWorld() {
player.onConnect("unnamed player");
blocks = [];
blocks.push(new Block(-1, -1, "#555", true, "normal"));
blocks.push(new Block(0, -1, "#a67", true, "spawn"));
blocks.push(new Block(1, -1, "#555", true, "normal"));
}
function getBlock(x, y) {
let value = blocks.find(o => !(o instanceof Player) && o.x == x && o.y == y);
if (typeof value === "undefined") {
return null;
}
else {
return value;
}
}
function placeBlock(block) {
blocks.push(block);
}
function removeBlock(x, y) {
blocks = blocks.filter(o => o instanceof Player || o.x != x || o.y != y);
}
function getPlayer(name) {
let value = blocks.find(o => o instanceof Player && o.name == name);
if (typeof value === "undefined") {
return null;
}
else {
return value;
}
}
function removePlayer(name) {
blocks = blocks.filter(o => !(o instanceof Player) || o.name != name);
}
function render() {
ctx.fillStyle = "#333";
ctx.fillRect(0, 0, width, height);
for (const block of blocks)
block.render();
for (const block of blocks)
block.renderText();
player.render();
player.renderText();
}
function tick() {
for (const block of blocks)
block.tick();
player.tick();
}
function renderTick() {
for (const block of blocks)
block.renderTick();
player.renderTick();
}
resetWorld();

View file

@ -1,53 +0,0 @@
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const width = 640;
const height = 480;
const server_ip = document.getElementById("server-ip");
const server_nick = document.getElementById("server-nick");
const connect_server = document.getElementById("connect-server");
const server_error = document.getElementById("server-error");
function wrapText(ctx, text, maxWidth) {
const lines = [];
let currentLine = '';
for (let i = 0; i < text.length; i++) {
const char = text[i];
const testLine = currentLine + char;
const testWidth = ctx.measureText(testLine).width;
if (testWidth > maxWidth && currentLine) {
lines.push(currentLine);
currentLine = char;
}
else {
currentLine = testLine;
}
}
if (currentLine) {
lines.push(currentLine);
}
return lines;
}
function lerp(a, b, alpha) {
return a + alpha * (b - a);
}
function setServerError(text) {
server_error.innerText = text;
}
connect_server.onclick = () => {
let ip = server_ip.value;
let nick = server_nick.value;
setServerError("");
if (ip.length == 0)
return setServerError("введите айпи пж");
if (nick.length == 0)
return setServerError("введите ник пж");
if (!ip.includes(":"))
ip += ":8000";
connectServer(ip, nick);
};
setInterval(tick, 1000 / 20);
setInterval(renderTick, 1000 / 60);
let renderTimer = () => {
render();
requestAnimationFrame(renderTimer);
};
requestAnimationFrame(renderTimer);

View file

@ -1,71 +0,0 @@
class Packet {
constructor(id, data) {
this.id = id;
this.data = data;
}
getId() { return this.id; }
getData() { return this.data; }
static fromString(data) {
return new Packet(data[0], data.slice(1).split("\n"));
}
}
class JoinPacket extends Packet {
constructor(name) {
super("J", [name]);
}
}
class MessagePacket extends Packet {
constructor(message) {
super("M", [message]);
}
}
class KeyPacket extends Packet {
constructor(key, pressed) {
super("K", [key, pressed ? "1" : "0"]);
}
}
class PlaceBlockPacket extends Packet {
constructor(x, y, type) {
super("P", [x.toString(), y.toString(), type]);
}
}
class DestroyBlockPacket extends Packet {
constructor(x, y) {
super("D", [x.toString(), y.toString()]);
}
}
class PositionPacket extends Packet {
constructor(x, y) {
super("X", [x.toString(), y.toString()]);
}
}
class VelocityPacket extends Packet {
constructor(x, y) {
super("V", [x.toString(), y.toString()]);
}
}
class Connection {
constructor(address, on_packet, on_close) {
this.socket = new WebSocket("ws://" + address, "cubic");
this.on_packet = on_packet;
this.on_close = on_close;
this.socket.onmessage = this._on_message;
this.socket.onclose = this._on_close;
this.socket.onerror = this._on_error;
}
_on_message(event) {
this.on_packet(Packet.fromString(event.data));
}
_on_close(event) {
this.on_close(null);
}
_on_error(event) {
this.on_close(event.toString());
}
close() {
this.socket.close();
}
send(packet) {
this.socket.send(packet.getId() + packet.getData());
}
}

View file

@ -1,347 +0,0 @@
class MainPlayer extends Player {
constructor() {
super(0.0, 0.0, "unnamed player", "#5e6", 0, 0);
this.reset();
this.conn = null;
}
reset() {
super.reset();
this.walk_speed = 1;
this.jump_speed = 2;
this.gravity_speed = 0.5;
this.controls_x = 0;
this.controls_jump = false;
this.block_type = null;
this.all_block_types = [
"normal", "normal", "normal", "normal", "normal",
"normal", "normal", "normal", "normal", "normal"
];
}
onConnect(name) {
this.x = 0.0;
this.y = 0.0;
this.velocity_x = 0.0;
this.velocity_y = 0.0;
camera.x = 0.0;
camera.y = 0.0;
chatOpened = false;
chatMessages = [];
this.name = name;
this.color = "#5e6";
blocks = [];
this.reset();
}
register() {
document.addEventListener("keydown", (e) => {
let key = e.code;
if (chatOpened) {
if (key == "Backspace") {
chatTyping = chatTyping.slice(0, chatTyping.length - 1);
}
else if (key == "Enter") {
if (chatTyping == "") {
chatOpened = false;
return;
}
this.sendPacket(new MessagePacket(chatTyping));
chatTyping = "";
chatOpened = false;
}
else if (key == "Escape") {
chatOpened = false;
}
else if (e.key.length == 1) {
chatTyping += e.key;
e.preventDefault();
return false;
}
}
else {
if (key == "KeyD") {
this.controls_x = 1;
}
else if (key == "KeyA") {
this.controls_x = -1;
}
else if (key == "Space") {
this.controls_jump = true;
e.preventDefault();
return false;
}
else if (key == "KeyR") {
if (this.conn == null) {
this.forceTeleport(0, 1);
}
}
else if (key == "KeyT") {
chatOpened = true;
}
if (e.key == "0")
this.block_type = null;
if ("123456789".includes(e.key))
this.block_type = this.all_block_types[parseInt(e.key) - 1];
if (allowed_key_to_send.includes(key)) {
this.sendPacket(new KeyPacket(key, true));
}
if (key == "Escape") {
this.closeConnection();
}
}
if (key == "F3") {
debugMode = !debugMode;
e.preventDefault();
return false;
}
});
document.addEventListener("keyup", (e) => {
let key = e.code;
if ((key == "KeyD" && this.controls_x == 1)
|| (key == "KeyA" && this.controls_x == -1)) {
this.controls_x = 0;
}
else if (key == "Space" && this.controls_jump) {
this.controls_jump = false;
}
if (allowed_key_to_send.includes(key)) {
this.sendPacket(new KeyPacket(key, false));
}
});
canvas.addEventListener("wheel", e => {
if (e.deltaY > 0) {
camera.size *= 0.5 * (e.deltaY / 114);
}
else {
camera.size *= 2 * (e.deltaY / -114);
}
e.preventDefault();
return false;
});
canvas.addEventListener("mousedown", e => {
let rect = canvas.getBoundingClientRect();
let size = 16 * camera.size;
let x = Math.round((e.clientX - rect.x) / size - (width / size / 2) + camera.x);
let y = Math.round((height - (e.clientY - rect.y)) / size - (height / size / 2) + camera.y);
if (e.buttons == 2 && this.block_type != null) {
if (this.conn == null) {
placeBlock(new Block(x, y, "#555", true, this.block_type));
}
this.sendPacket(new PlaceBlockPacket(x, y, this.block_type));
}
else if (e.buttons == 1) {
if (this.conn == null) {
removeBlock(x, y);
}
this.sendPacket(new DestroyBlockPacket(x, y));
}
});
}
sendPacket(packet) {
if (this.conn != null) {
this.conn.send(packet);
}
}
closeConnection() {
if (this.conn != null)
this.conn.close();
this.conn = null;
}
onPacket(packet) {
let packet_id = packet.getId();
let packet_data = packet.getData();
if (packet_id == "K") {
setServerError(packet_data[0]);
this.closeConnection();
}
if (packet_id == "N") {
this.name = packet_data[0];
}
if (packet_id == "C") {
this.color = packet_data[0];
}
if (packet_id == "M") {
chatMessages.unshift(...packet_data);
}
if (packet_id == "R") {
this.velocity_x = parseFloat(packet_data[0]) - this.x + parseFloat(packet_data[2]);
this.velocity_y = parseFloat(packet_data[1]) - this.y + parseFloat(packet_data[3]);
}
if (packet_id == "P") {
let x = parseFloat(packet_data[0]);
let y = parseFloat(packet_data[1]);
this.x = x;
this.y = y;
}
if (packet_id == "V") {
let x = parseFloat(packet_data[0]);
let y = parseFloat(packet_data[1]);
this.velocity_x = x;
this.velocity_y = y;
}
if (packet_id == "S") {
let speed_type = packet_data[0];
let speed = parseFloat(packet_data[1]);
if (speed_type == "W") {
this.walk_speed = speed;
}
else if (speed_type == "J") {
this.jump_speed = speed;
}
else if (speed_type == "G") {
this.gravity_speed = speed;
}
}
if (packet_id == "W") {
for (const data of packet_data) {
let type = data[0];
let create = data[1] == "1";
let params = data.slice(2).split(",");
if (type == "B") {
let x = parseFloat(params[0]);
let y = parseFloat(params[1]);
if (create) {
let collides = params[2] == "1";
let type = params[3];
let color = params[4];
let block = getBlock(x, y);
if (block != null) {
block.x = x;
block.y = y;
block.color = color;
block.collides = collides;
block.type = type;
}
else {
placeBlock(new Block(x, y, color, collides, type));
}
}
else {
removeBlock(x, y);
}
}
else if (type == "P") {
let name = params[0];
if (create) {
let x = parseFloat(params[1]);
let y = parseFloat(params[2]);
let vel_x = parseFloat(params[3]);
let vel_y = parseFloat(params[4]);
let color = params[5];
let player = getPlayer(name);
if (player != null) {
player.x = x;
player.y = y;
player.color = color;
player.velocity_x = vel_x;
player.velocity_y = vel_y;
}
else {
placeBlock(new Player(x, y, name, color, vel_x, vel_y));
}
}
else {
removePlayer(name);
}
}
}
}
if (packet_id == "B") {
this.all_block_types = packet_data.slice(0, 9);
this.block_type = null;
}
}
tick() {
super.tick(false);
let vel_x = this.velocity_x;
let vel_y = this.velocity_y;
this.velocity_x += this.controls_x * this.walk_speed;
if (this.controls_jump && this.on_ground) {
this.velocity_y += this.jump_speed;
this.on_ground = false;
}
else {
this.velocity_y -= this.gravity_speed;
}
this.collide();
ticksAlive++;
this.sendPacket(new VelocityPacket(this.velocity_x - vel_x, this.velocity_y - vel_y));
this.sendPacket(new PositionPacket(this.x, this.y));
}
render() {
super.render();
camera.x = Math.round(lerp(camera.x, this.x, 0.075) * 1000) / 1000;
camera.y = Math.round(lerp(camera.y, this.y, 0.075) * 1000) / 1000;
}
renderText() {
super.renderText();
if (this.block_type != null) {
ctx.fillStyle = "#76d";
ctx.font = "15px monospace";
ctx.fillText("selected: " + this.block_type, 0, 15);
}
if (debugMode) {
ctx.fillStyle = "#de7";
ctx.font = "20px monospace";
ctx.fillText("x: " + this.x, 0, 20);
ctx.fillText("y: " + this.y, 0, 40);
ctx.fillText("velocity_x: " + this.velocity_x, 0, 60);
ctx.fillText("velocity_y: " + this.velocity_y, 0, 80);
ctx.fillText("camera.x: " + camera.x, 0, 100);
ctx.fillText("camera.y: " + camera.y, 0, 120);
}
if (!chatOpened) {
ctx.fillStyle = "#22222288";
ctx.fillRect(5, height - 35, width * 0.4, 30);
ctx.fillStyle = "#aaaaaa88";
ctx.font = "15px monospace";
ctx.fillText("Нажмите T для чата", 15, height - 15);
}
else {
ctx.fillStyle = "#22222288";
ctx.fillRect(5, height - 35, width - 10, 30);
ctx.save();
ctx.beginPath();
ctx.moveTo(5, height - 35);
ctx.lineTo(width - 5, height - 35);
ctx.lineTo(width - 5, height - 5);
ctx.lineTo(5, height - 5);
ctx.lineTo(5, height - 35);
ctx.closePath();
ctx.clip();
ctx.font = "15px monospace";
if (chatTyping.length == 0) {
ctx.fillStyle = "#aaaaaa88";
ctx.fillText("Напишите сообщение...", 15, height - 15);
}
else {
ctx.fillStyle = "#ffffff";
let text_width = ctx.measureText(chatTyping).width;
ctx.fillText(chatTyping, Math.min(10, width - text_width - 10), height - 15);
}
ctx.restore();
}
if (chatMessages.length > 0) {
let draw_message = (message) => {
let lines = wrapText(ctx, message, message_width - 20);
let height = lines.length * 20 + 5 + 5;
let top = message_bottom - height;
ctx.fillStyle = "#22222288";
ctx.fillRect(5, top, message_width, height);
let y = 5;
for (let line of lines) {
ctx.fillStyle = "#ffffff";
ctx.fillText(line, 15, top + y + 15);
y += 5 + 20;
}
message_bottom -= height + 5;
};
let message_width = width * 0.4;
let message_bottom = height - 35 - 5;
if (chatOpened) {
chatMessages.forEach(draw_message);
}
else {
draw_message(chatMessages[0]);
}
}
}
}

View file

@ -1,673 +0,0 @@
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const width = 640;
const height = 480;
const server_ip = document.getElementById("server-ip");
const server_nick = document.getElementById("server-nick");
const connect_server = document.getElementById("connect-server");
const server_error = document.getElementById("server-error");
function wrapText(ctx, text, maxWidth) {
const lines = [];
let currentLine = '';
for (let i = 0; i < text.length; i++) {
const char = text[i];
const testLine = currentLine + char;
const testWidth = ctx.measureText(testLine).width;
if (testWidth > maxWidth && currentLine) {
lines.push(currentLine);
currentLine = char;
}
else {
currentLine = testLine;
}
}
if (currentLine) {
lines.push(currentLine);
}
return lines;
}
function lerp(a, b, alpha) {
return a + alpha * (b - a);
}
function setServerError(text) {
server_error.innerText = text;
}
connect_server.onclick = () => {
let ip = server_ip.value;
let nick = server_nick.value;
setServerError("");
if (ip.length == 0)
return setServerError("введите айпи пж");
if (nick.length == 0)
return setServerError("введите ник пж");
if (!ip.includes(":"))
ip += ":8000";
connectServer(ip, nick);
};
setInterval(tick, 1000 / 20);
setInterval(renderTick, 1000 / 60);
let renderTimer = () => {
render();
requestAnimationFrame(renderTimer);
};
requestAnimationFrame(renderTimer);
class Block {
constructor(x, y, color, collides, type) {
this.x = x;
this.y = y;
this.color = color;
this.collides = collides;
this.type = type;
}
render() {
let rect = this.translate_to_camera();
if (this.is_need_render(rect)) {
ctx.fillStyle = this.color;
ctx.fillRect(...rect);
}
}
is_need_render(rect) {
return rect[0] + rect[2] > 0 || rect[1] + rect[3] > 0 || rect[0] < width || rect[1] < height;
}
translate_to_camera() {
let size = camera.size * 16;
return [
this.x * size - size / 2 + (width / 2 - camera.x * size),
height - (this.y + 1) * size + size / 2 - (height / 2 - camera.y * size),
size,
size
];
}
tick() {
}
renderTick() {
}
on_collide(player, x, y) {
if (x != 0)
player.velocity_x = this.x + x - player.x;
if (y != 0)
player.velocity_y = this.y + y - player.y;
}
renderText() {
}
}
class Player extends Block {
constructor(x, y, name, color, velocity_x, velocity_y) {
super(x, y, color, true, null);
this.velocity_x = velocity_x;
this.velocity_y = velocity_y;
this.name = name;
}
reset() {
this.on_ground = false;
}
on_collide(player, x, y) {
super.on_collide(player, x, y);
}
tick(collide = true) {
this.x = Math.round(this.x * 100) / 100;
this.y = Math.round(this.y * 100) / 100;
this.velocity_x = Math.round(this.velocity_x * 100) / 100;
this.velocity_y = Math.round(this.velocity_y * 100) / 100;
if (collide)
this.collide();
}
collide() {
this.on_ground = false;
for (const block of blocks) {
if (!block.collides)
continue;
let collide_x = 0;
let collide_y = 0;
if (this.x > block.x - 1 && this.x < block.x + 1) {
if (this.y > block.y && this.y + this.velocity_y - 1 < block.y) {
this.on_ground = true;
collide_y = 1;
}
if (this.y < block.y && this.y + this.velocity_y > block.y - 1)
collide_y = -1;
}
if (this.y > block.y - 1 && this.y < block.y + 1) {
if (this.x > block.x && this.x + this.velocity_x - 1 < block.x)
collide_x = 1;
if (this.x < block.x && this.x + this.velocity_x > block.x - 1)
collide_x = -1;
}
block.on_collide(this, collide_x, collide_y);
}
}
renderTick() {
this.velocity_x *= 0.5;
this.velocity_y *= 0.5;
this.x += this.velocity_x;
this.y += this.velocity_y;
}
renderText() {
super.renderText();
let rect = this.translate_to_camera();
if (this.is_need_render(rect)) {
ctx.fillStyle = "#ddd";
ctx.font = "15px monospace";
let width = ctx.measureText(this.name).width;
ctx.fillText(this.name, rect[0] + rect[2] / 2 - width / 2, rect[1] - 5);
}
}
teleport(x, y) {
this.velocity_x = x - this.x;
this.velocity_y = y - this.y;
}
forceTeleport(x, y) {
this.x = x;
this.y = y;
this.velocity_x = 0;
this.velocity_y = 0;
}
}
class Packet {
constructor(id, data) {
this.id = id;
this.data = data;
}
getId() { return this.id; }
getData() { return this.data; }
static fromString(data) {
return new Packet(data[0], data.slice(1).split("\n"));
}
}
class JoinPacket extends Packet {
constructor(name) {
super("J", [name]);
}
}
class MessagePacket extends Packet {
constructor(message) {
super("M", [message]);
}
}
class KeyPacket extends Packet {
constructor(key, pressed) {
super("K", [key, pressed ? "1" : "0"]);
}
}
class PlaceBlockPacket extends Packet {
constructor(x, y, type) {
super("P", [x.toString(), y.toString(), type]);
}
}
class DestroyBlockPacket extends Packet {
constructor(x, y) {
super("D", [x.toString(), y.toString()]);
}
}
class PositionPacket extends Packet {
constructor(x, y) {
super("X", [x.toString(), y.toString()]);
}
}
class VelocityPacket extends Packet {
constructor(x, y) {
super("V", [x.toString(), y.toString()]);
}
}
class Connection {
constructor(address, on_packet, on_close) {
this.socket = new WebSocket("ws://" + address, "cubic");
this.on_packet = on_packet;
this.on_close = on_close;
this.socket.onmessage = this._on_message;
this.socket.onclose = this._on_close;
this.socket.onerror = this._on_error;
}
_on_message(event) {
this.on_packet(Packet.fromString(event.data));
}
_on_close(event) {
this.on_close(null);
}
_on_error(event) {
this.on_close(event.toString());
}
close() {
this.socket.close();
}
send(packet) {
this.socket.send(packet.getId() + packet.getData());
}
}
class MainPlayer extends Player {
constructor() {
super(0.0, 0.0, "unnamed player", "#5e6", 0, 0);
this.reset();
this.conn = null;
}
reset() {
super.reset();
this.walk_speed = 1;
this.jump_speed = 2;
this.gravity_speed = 0.5;
this.controls_x = 0;
this.controls_jump = false;
this.block_type = null;
this.all_block_types = [
"normal", "normal", "normal", "normal", "normal",
"normal", "normal", "normal", "normal", "normal"
];
}
onConnect(name) {
this.x = 0.0;
this.y = 0.0;
this.velocity_x = 0.0;
this.velocity_y = 0.0;
camera.x = 0.0;
camera.y = 0.0;
chatOpened = false;
chatMessages = [];
this.name = name;
this.color = "#5e6";
blocks = [];
this.reset();
}
register() {
document.addEventListener("keydown", (e) => {
let key = e.code;
if (chatOpened) {
if (key == "Backspace") {
chatTyping = chatTyping.slice(0, chatTyping.length - 1);
}
else if (key == "Enter") {
if (chatTyping == "") {
chatOpened = false;
return;
}
this.sendPacket(new MessagePacket(chatTyping));
chatTyping = "";
chatOpened = false;
}
else if (key == "Escape") {
chatOpened = false;
}
else if (e.key.length == 1) {
chatTyping += e.key;
e.preventDefault();
return false;
}
}
else {
if (key == "KeyD") {
this.controls_x = 1;
}
else if (key == "KeyA") {
this.controls_x = -1;
}
else if (key == "Space") {
this.controls_jump = true;
e.preventDefault();
return false;
}
else if (key == "KeyR") {
if (this.conn == null) {
this.forceTeleport(0, 1);
}
}
else if (key == "KeyT") {
chatOpened = true;
}
if (e.key == "0")
this.block_type = null;
if ("123456789".includes(e.key))
this.block_type = this.all_block_types[parseInt(e.key) - 1];
if (allowed_key_to_send.includes(key)) {
this.sendPacket(new KeyPacket(key, true));
}
if (key == "Escape") {
this.closeConnection();
}
}
if (key == "F3") {
debugMode = !debugMode;
e.preventDefault();
return false;
}
});
document.addEventListener("keyup", (e) => {
let key = e.code;
if ((key == "KeyD" && this.controls_x == 1)
|| (key == "KeyA" && this.controls_x == -1)) {
this.controls_x = 0;
}
else if (key == "Space" && this.controls_jump) {
this.controls_jump = false;
}
if (allowed_key_to_send.includes(key)) {
this.sendPacket(new KeyPacket(key, false));
}
});
canvas.addEventListener("wheel", e => {
if (e.deltaY > 0) {
camera.size *= 0.5 * (e.deltaY / 114);
}
else {
camera.size *= 2 * (e.deltaY / -114);
}
e.preventDefault();
return false;
});
canvas.addEventListener("mousedown", e => {
let rect = canvas.getBoundingClientRect();
let size = 16 * camera.size;
let x = Math.round((e.clientX - rect.x) / size - (width / size / 2) + camera.x);
let y = Math.round((height - (e.clientY - rect.y)) / size - (height / size / 2) + camera.y);
if (e.buttons == 2 && this.block_type != null) {
if (this.conn == null) {
placeBlock(new Block(x, y, "#555", true, this.block_type));
}
this.sendPacket(new PlaceBlockPacket(x, y, this.block_type));
}
else if (e.buttons == 1) {
if (this.conn == null) {
removeBlock(x, y);
}
this.sendPacket(new DestroyBlockPacket(x, y));
}
});
}
sendPacket(packet) {
if (this.conn != null) {
this.conn.send(packet);
}
}
closeConnection() {
if (this.conn != null)
this.conn.close();
this.conn = null;
}
onPacket(packet) {
let packet_id = packet.getId();
let packet_data = packet.getData();
if (packet_id == "K") {
setServerError(packet_data[0]);
this.closeConnection();
}
if (packet_id == "N") {
this.name = packet_data[0];
}
if (packet_id == "C") {
this.color = packet_data[0];
}
if (packet_id == "M") {
chatMessages.unshift(...packet_data);
}
if (packet_id == "R") {
this.velocity_x = parseFloat(packet_data[0]) - this.x + parseFloat(packet_data[2]);
this.velocity_y = parseFloat(packet_data[1]) - this.y + parseFloat(packet_data[3]);
}
if (packet_id == "P") {
let x = parseFloat(packet_data[0]);
let y = parseFloat(packet_data[1]);
this.x = x;
this.y = y;
}
if (packet_id == "V") {
let x = parseFloat(packet_data[0]);
let y = parseFloat(packet_data[1]);
this.velocity_x = x;
this.velocity_y = y;
}
if (packet_id == "S") {
let speed_type = packet_data[0];
let speed = parseFloat(packet_data[1]);
if (speed_type == "W") {
this.walk_speed = speed;
}
else if (speed_type == "J") {
this.jump_speed = speed;
}
else if (speed_type == "G") {
this.gravity_speed = speed;
}
}
if (packet_id == "W") {
for (const data of packet_data) {
let type = data[0];
let create = data[1] == "1";
let params = data.slice(2).split(",");
if (type == "B") {
let x = parseFloat(params[0]);
let y = parseFloat(params[1]);
if (create) {
let collides = params[2] == "1";
let type = params[3];
let color = params[4];
let block = getBlock(x, y);
if (block != null) {
block.x = x;
block.y = y;
block.color = color;
block.collides = collides;
block.type = type;
}
else {
placeBlock(new Block(x, y, color, collides, type));
}
}
else {
removeBlock(x, y);
}
}
else if (type == "P") {
let name = params[0];
if (create) {
let x = parseFloat(params[1]);
let y = parseFloat(params[2]);
let vel_x = parseFloat(params[3]);
let vel_y = parseFloat(params[4]);
let color = params[5];
let player = getPlayer(name);
if (player != null) {
player.x = x;
player.y = y;
player.color = color;
player.velocity_x = vel_x;
player.velocity_y = vel_y;
}
else {
placeBlock(new Player(x, y, name, color, vel_x, vel_y));
}
}
else {
removePlayer(name);
}
}
}
}
if (packet_id == "B") {
this.all_block_types = packet_data.slice(0, 9);
this.block_type = null;
}
}
tick() {
super.tick(false);
let vel_x = this.velocity_x;
let vel_y = this.velocity_y;
this.velocity_x += this.controls_x * this.walk_speed;
if (this.controls_jump && this.on_ground) {
this.velocity_y += this.jump_speed;
this.on_ground = false;
}
else {
this.velocity_y -= this.gravity_speed;
}
this.collide();
ticksAlive++;
this.sendPacket(new VelocityPacket(this.velocity_x - vel_x, this.velocity_y - vel_y));
this.sendPacket(new PositionPacket(this.x, this.y));
}
render() {
super.render();
camera.x = Math.round(lerp(camera.x, this.x, 0.075) * 1000) / 1000;
camera.y = Math.round(lerp(camera.y, this.y, 0.075) * 1000) / 1000;
}
renderText() {
super.renderText();
if (this.block_type != null) {
ctx.fillStyle = "#76d";
ctx.font = "15px monospace";
ctx.fillText("selected: " + this.block_type, 0, 15);
}
if (debugMode) {
ctx.fillStyle = "#de7";
ctx.font = "20px monospace";
ctx.fillText("x: " + this.x, 0, 20);
ctx.fillText("y: " + this.y, 0, 40);
ctx.fillText("velocity_x: " + this.velocity_x, 0, 60);
ctx.fillText("velocity_y: " + this.velocity_y, 0, 80);
ctx.fillText("camera.x: " + camera.x, 0, 100);
ctx.fillText("camera.y: " + camera.y, 0, 120);
}
if (!chatOpened) {
ctx.fillStyle = "#22222288";
ctx.fillRect(5, height - 35, width * 0.4, 30);
ctx.fillStyle = "#aaaaaa88";
ctx.font = "15px monospace";
ctx.fillText("Нажмите T для чата", 15, height - 15);
}
else {
ctx.fillStyle = "#22222288";
ctx.fillRect(5, height - 35, width - 10, 30);
ctx.save();
ctx.beginPath();
ctx.moveTo(5, height - 35);
ctx.lineTo(width - 5, height - 35);
ctx.lineTo(width - 5, height - 5);
ctx.lineTo(5, height - 5);
ctx.lineTo(5, height - 35);
ctx.closePath();
ctx.clip();
ctx.font = "15px monospace";
if (chatTyping.length == 0) {
ctx.fillStyle = "#aaaaaa88";
ctx.fillText("Напишите сообщение...", 15, height - 15);
}
else {
ctx.fillStyle = "#ffffff";
let text_width = ctx.measureText(chatTyping).width;
ctx.fillText(chatTyping, Math.min(10, width - text_width - 10), height - 15);
}
ctx.restore();
}
if (chatMessages.length > 0) {
let draw_message = (message) => {
let lines = wrapText(ctx, message, message_width - 20);
let height = lines.length * 20 + 5 + 5;
let top = message_bottom - height;
ctx.fillStyle = "#22222288";
ctx.fillRect(5, top, message_width, height);
let y = 5;
for (let line of lines) {
ctx.fillStyle = "#ffffff";
ctx.fillText(line, 15, top + y + 15);
y += 5 + 20;
}
message_bottom -= height + 5;
};
let message_width = width * 0.4;
let message_bottom = height - 35 - 5;
if (chatOpened) {
chatMessages.forEach(draw_message);
}
else {
draw_message(chatMessages[0]);
}
}
}
}
var ticksAlive = 0;
var debugMode = false;
var camera = {
x: 0.0,
y: 0.0,
size: 1.5
};
var chatOpened = false;
var chatMessages = [];
var chatTyping = "";
var player = new MainPlayer();
player.register();
var blocks = [];
const allowed_key_to_send = [
"KeyR", "KeyW", "KeyE", "KeyQ", "KeyS",
"Numpad1", "Numpad2", "Numpad3", "Numpad4", "Numpad5",
"Numpad6", "Numpad7", "Numpad8", "Numpad9", "Numpad0",
"ShiftLeft", "ControlLeft", "Enter",
"F1", "F2", "KeyZ", "KeyX", "KeyC"
];
function connectServer(address, name) {
player.closeConnection();
player.onConnect(name);
try {
let conn = new Connection(address, player.onPacket, (e) => {
player.conn = null;
setServerError(e == null ? "Connection closed due to error" : e);
resetWorld();
});
conn.send(new JoinPacket(name));
}
catch (exception) {
setServerError(exception);
}
}
function resetWorld() {
player.onConnect("unnamed player");
blocks = [];
blocks.push(new Block(-1, -1, "#555", true, "normal"));
blocks.push(new Block(0, -1, "#a67", true, "spawn"));
blocks.push(new Block(1, -1, "#555", true, "normal"));
}
function getBlock(x, y) {
let value = blocks.find(o => !(o instanceof Player) && o.x == x && o.y == y);
if (typeof value === "undefined") {
return null;
}
else {
return value;
}
}
function placeBlock(block) {
blocks.push(block);
}
function removeBlock(x, y) {
blocks = blocks.filter(o => o instanceof Player || o.x != x || o.y != y);
}
function getPlayer(name) {
let value = blocks.find(o => o instanceof Player && o.name == name);
if (typeof value === "undefined") {
return null;
}
else {
return value;
}
}
function removePlayer(name) {
blocks = blocks.filter(o => !(o instanceof Player) || o.name != name);
}
function render() {
ctx.fillStyle = "#333";
ctx.fillRect(0, 0, width, height);
for (const block of blocks)
block.render();
for (const block of blocks)
block.renderText();
player.render();
player.renderText();
}
function tick() {
for (const block of blocks)
block.tick();
player.tick();
}
function renderTick() {
for (const block of blocks)
block.renderTick();
player.renderTick();
}
resetWorld();