reduce update packet size by ~70%

This commit is contained in:
Asraelite 2016-03-29 01:14:32 +01:00
parent 1af386d9f5
commit 0906441246
20 changed files with 219 additions and 143 deletions

View file

@ -18,7 +18,6 @@ class Net {
this.socket.on('update', data => { this.socket.on('update', data => {
game.world.update(data); game.world.update(data);
//console.log('.');
}); });
this.socket.on('world', data => { this.socket.on('world', data => {

View file

@ -31,8 +31,7 @@ class Renderer {
if (state == 'connecting' || state == 'disconnected') { if (state == 'connecting' || state == 'disconnected') {
pallet.clear(); pallet.clear();
pallet.fill('#111'); pallet.fill('#111');
var str = state == 'connecting' ? 'Connecting' : 'Shit\'s ' + var str = state == 'connecting' ? 'Connecting' : 'Disconnected';
'diconnected, yo!';
pallet.text(str, canvas.width / 2, canvas.height / 2, '#fff', pallet.text(str, canvas.width / 2, canvas.height / 2, '#fff',
'FreePixel', 16, 'center', 'middle'); 'FreePixel', 16, 'center', 'middle');
return; return;

View file

@ -16,9 +16,9 @@ Renderer.prototype.renderShip = (pallet, ship) => {
pallet.view(x + vx, y + vy, false, pos.r); pallet.view(x + vx, y + vy, false, pos.r);
let ts = ship.size / 2; let ts = ship.size / 2;
for (let i = 0; i < ship.mounts.length; i++) { for (let i = 0; i < ship.fixtures.length; i++) {
if (ship.turrets[i]) { if (ship.fixtures[i]) {
pallet.image(turr, ship.mounts[i][0] - ts, ship.mounts[i][1] - ts, 0); pallet.image(turr, ship.fixtures[i][0] - ts, ship.fixtures[i][1] - ts, 0);
} }
} }
pallet.image(ship.team == 'a' ? teama : teamb, 0, 0, 0); pallet.image(ship.team == 'a' ? teama : teamb, 0, 0, 0);

View file

@ -6,7 +6,7 @@ class Asteroid extends Body {
} }
updateType(data) { updateType(data) {
this.debug = data[6]; this.debug = data.debug;
} }
tick() { tick() {

View file

@ -2,17 +2,17 @@
class Body { class Body {
constructor(data) { constructor(data) {
this.x = data.delta[0]; console.log(data);
this.y = data.delta[1]; this.interface = data.interface;
this.xvel = data.delta[2]; let s = this.interface.order.length + this.interface.fixtures;
this.yvel = data.delta[3]; this.interface.size = s;
this.r = data.delta[4];
this.rvel = data.delta[5];
this.id = data.id this.id = data.id
this.frame = data.frame; this.frame = data.frame;
this.fixtures = data.fixtures;
this.b2body = false; this.b2body = false;
this.updated = 0; this.updated = 0;
game.world.update(data.delta);
this.com = { this.com = {
x: 0, x: 0,
@ -40,15 +40,19 @@ class Body {
} }
update(data) { update(data) {
this.x = data[0]; let values = {};
this.y = data[1]; Array.from(data).map((v, i) => {
this.xvel = data[2] values[this.interface.order[i]] = v
this.yvel = data[3]; });
this.r = data[4]; this.x = values.x;
this.rvel = data[5]; this.y = values.y;
this.xvel = values.xvel;
this.yvel = values.yvel;
this.r = values.r;
this.rvel = values.rvel;
this.updated = 10; this.updated = 10;
this.updateType(data); this.updateType(values);
} }
updateType() { updateType() {
@ -56,6 +60,6 @@ class Body {
} }
tick() { tick() {
} }
} }

View file

@ -1,6 +1,5 @@
class Ship extends Body { class Ship extends Body {
constructor(data) { constructor(data) {
console.log(data);
super(data); super(data);
this.player = new Player(data.name, data.team, this); this.player = new Player(data.name, data.team, this);
this.team = data.team; this.team = data.team;
@ -8,8 +7,6 @@ class Ship extends Body {
this.hull = '01'; this.hull = '01';
this.thrust = {}; this.thrust = {};
this.power = data.power; this.power = data.power;
this.mounts = data.mounts;
this.turrets = data.turrets;
this.size = { this.size = {
'small': 8, 'small': 8,
'medium': 16, 'medium': 16,
@ -21,10 +18,10 @@ class Ship extends Body {
updateType(data) { updateType(data) {
this.thrust = { this.thrust = {
forward: data[6] forward: data.thrustForward
} }
this.debug = data[9]; this.debug = data.debug;
} }
tick() { tick() {

View file

@ -0,0 +1,8 @@
class Turret {
constructor(ship, type, pos) {
this.ship = ship;
this.type = type;
this.pos = pos;
this.traversal = 0;
}
}

View file

@ -1,4 +1,4 @@
var SCALE = 32; const SCALE = 32;
class World { class World {
constructor() { constructor() {
@ -44,16 +44,19 @@ class World {
}; };
update(data) { update(data) {
for (var id in data) { let array = new Float32Array(data);
if (!this.bodies[id]) { let i = 0;
while (i < array.length) {
let id = array[i++];
let body = this.bodies[id];
if (!body) {
game.net.send('requestBodyData', id); game.net.send('requestBodyData', id);
continue; return;
} }
var body = this.bodies[id]; body.update(array.slice(i, i + body.interface.size));
body.update(data[id]); i += body.interface.size;
if (data[id].destroy) delete this.bodies[id];
} }
}; };

View file

@ -76,11 +76,14 @@
"Salal Berry", "Salal Berry",
"Salak", "Salak",
"Satsuma", "Satsuma",
"Soursop",
"Star Fruit", "Star Fruit",
"Strawberry", "Strawberry",
"Tamarillo", "Tamarillo",
"Tamarind", "Tamarind",
"Ugli Fruit" "Ugli Fruit",
"Yuzu",
"Ziziphus"
], ],
"adjectives": { "adjectives": {
"a": [ "a": [
@ -159,7 +162,8 @@
"Perfect", "Perfect",
"Pitiful", "Pitiful",
"Paranoid", "Paranoid",
"Pink" "Pink",
"Porous"
], ],
"q": [ "q": [
"Quivering", "Quivering",
@ -172,7 +176,8 @@
"s": [ "s": [
"Stupid", "Stupid",
"Silly", "Silly",
"Smart" "Smart",
"Slimy"
], ],
"t": [ "t": [
"Terrific", "Terrific",
@ -195,10 +200,12 @@
"Xenophobic" "Xenophobic"
], ],
"y": [ "y": [
"Yellow" "Yellow",
"Useful"
], ],
"z": [ "z": [
"Zany" "Zany",
"Zealous"
] ]
} }
} }

View file

@ -11,7 +11,7 @@ class Player {
this.lastAction = Date.now(); this.lastAction = Date.now();
this.connection = connection; this.connection = connection;
this.name = this.randomName(); this.name = this.randomName();
this.delta = {}; this.delta = [];
this.chatCooldown = 0; this.chatCooldown = 0;
} }
@ -20,6 +20,10 @@ class Player {
this.room.remove(this); this.room.remove(this);
} }
applyDelta(data) {
this.delta = this.delta.concat(data);
}
updateInputs(data) { updateInputs(data) {
this.ship.updateInputs(data); this.ship.updateInputs(data);
this.lastAction = Date.now(); this.lastAction = Date.now();
@ -49,9 +53,9 @@ class Player {
} }
sendUpdate() { sendUpdate() {
if (Object.keys(this.delta).length == 0) return; if (this.delta.length == 0) return;
this.connection.send('update', this.delta); this.connection.send('update', this.delta);
this.delta = {}; this.delta = [];
} }
tick() { tick() {

View file

@ -13,6 +13,14 @@ class Room {
this.teamB = new Set(); this.teamB = new Set();
this.world = new World(this); this.world = new World(this);
this.name = (Math.random() * 100000 | 0).toString(36); this.name = (Math.random() * 100000 | 0).toString(36);
this.tps = 60;
this.idGenerator = (function*() {
let i = 0;
while (true)
yield i++;
})();
this.gameServer = gameServer; this.gameServer = gameServer;
this.io = this.gameServer.net.io; this.io = this.gameServer.net.io;
@ -46,6 +54,10 @@ class Room {
this.message('roomLeave', player.name, 'team' + player.team); this.message('roomLeave', player.name, 'team' + player.team);
} }
generateId() {
return this.idGenerator.next().value;
}
setTeam(player, team) { setTeam(player, team) {
this.teamA.delete(player); this.teamA.delete(player);
this.teamB.delete(player); this.teamB.delete(player);
@ -58,9 +70,9 @@ class Room {
player.connection.drop(); player.connection.drop();
} }
update(self) { update() {
//if (this.world.tickCount % 100 == 0) this.world.tick();
self.players.forEach(player => { this.players.forEach(player => {
player.sendUpdate(); player.sendUpdate();
if (Date.now() - player.lastAction > 10000) { if (Date.now() - player.lastAction > 10000) {
//this.kick(player); //this.kick(player);
@ -75,7 +87,7 @@ class Room {
chat(player, message) { chat(player, message) {
wingbase.log(`${this.name}/${player.name}: ${message}`); wingbase.log(`${this.name}/${player.name}: ${message}`);
this.chatCooldown++; this.chatCooldown++;
this.io.to(this.name).emit('chat', { this.io.to(this.name).emit('chat', {
type: 'player', type: 'player',
@ -104,6 +116,7 @@ class Room {
let data = { let data = {
playerShipId: player.ship.id, playerShipId: player.ship.id,
bounds: this.world.bounds, bounds: this.world.bounds,
tps: this.tps,
bodies: Array.from(this.world.bodies).map(b => b.packFull()) bodies: Array.from(this.world.bodies).map(b => b.packFull())
}; };
@ -113,7 +126,8 @@ class Room {
start() { start() {
this.world.populate(); this.world.populate();
this.world.start(); this.world.start();
this.interval = setInterval(_ => this.update(this), 1 / 60); let wait = 1 / this.tps * 1000;
this.interval = setInterval(this.update.bind(this), wait);
} }
stop() { stop() {

View file

@ -4,17 +4,19 @@ const Body = require('./body.js');
class Asteroid extends Body { class Asteroid extends Body {
constructor(world, pos, size) { constructor(world, pos, size) {
super(world); super(world, pos);
this.x = pos.x;
this.y = pos.y;
this.debug = 0; this.debug = 0;
this.size = size;
this.type = 'asteroid'; this.type = 'asteroid';
this.size = size;
this.frame = this.randomFrame(); this.frame = this.randomFrame();
this.interface.order.push.apply(this.interface.order, [
'debug'
]);
this.interface.type = 'asteroid';
} }
randomFrame() { randomFrame() {
@ -34,13 +36,8 @@ class Asteroid extends Body {
return [this.debug]; return [this.debug];
} }
packFull() { packTypeFull() {
return { return {};
type: 'asteroid',
id: this.id,
frame: this.frame,
delta: this.packDelta()
}
} }
} }

View file

@ -2,19 +2,37 @@
const uuid = require('uuid'); const uuid = require('uuid');
const Mount = require('./turret/mount.js');
const b2Vec2 = require('box2d-html5').b2Vec2; const b2Vec2 = require('box2d-html5').b2Vec2;
class Body { class Body {
constructor(world) { constructor(world, data) {
this.x = 0; data = data || {};
this.y = 0;
this.r = 0;
this.b2body = false;
this.type = 'asteroid';
this.mounts = [];
this.health = 1;
this.world = world; this.world = world;
this.id = uuid.v4().slice(0, 8); this.id = this.world.room.generateId();
this.type = 'body';
this.b2body = false;
this.mounts = data.mounts || [];
this.health = data.health || 1;
this.mounts = this.mounts.map(m => new Mount(this, m));
let fixtures = data.fixtures || [];
this.fixtures = this.mounts.map((m, i) => fixtures[i] || 0);
this.interface = {
order: [
'x',
'y',
'xvel',
'yvel',
'r',
'rvel'
],
type: 'body',
fixtures: this.fixtures.length
};
} }
destruct() { destruct() {
@ -23,7 +41,7 @@ class Body {
} }
applyDelta() { applyDelta() {
this.world.applyDelta(this.id, this.packDelta()); this.world.applyDelta(this.packDelta());
} }
applyForce(x, y, center) { applyForce(x, y, center) {
@ -74,8 +92,13 @@ class Body {
let rot = this.b2body.GetAngleRadians(); let rot = this.b2body.GetAngleRadians();
let rvel = this.b2body.GetAngularVelocity(); let rvel = this.b2body.GetAngularVelocity();
// Simple array to save bandwidth. let values = [this.id, pos.x, pos.y, vel.x, vel.y, rot, rvel];
return [pos.x, pos.y, vel.x, vel.y, rot, rvel].concat(this.packTypeDelta()); values = values.concat(this.packTypeDelta());
this.mounts.forEach(m => {
values = values.concat(m.packDelta());
});
return values;
} }
packTypeDelta() { packTypeDelta() {
@ -83,11 +106,24 @@ class Body {
} }
packFull() { packFull() {
return { let packet = {
type: 'body', type: this.type,
id: this.id, id: this.id,
delta: this.packDelta() frame: this.frame,
fixtures: this.mounts.map(m => m.packFull()),
delta: this.packDelta(),
interface: this.interface
} }
let typePacket = this.packTypeFull();
for (let i in typePacket)
packet[i] = typePacket[i];
return packet;
}
packTypeFull() {
return {};
} }
get com() { get com() {

View file

@ -5,13 +5,9 @@ const Rope = require('../../copula/rope.js');
class Grapple extends Projectile { class Grapple extends Projectile {
constructor(world, pos, source) { constructor(world, pos, source) {
super(world); // pos.x *= 32, pos.y *= 32, idk why
super(world, pos);
this.x = pos.x * 32;
this.y = pos.y * 32;
this.xvel = pos.xvel;
this.yvel = pos.yvel;
this.r = pos.r;
this.xvel += Math.cos(this.r) * 0.25; this.xvel += Math.cos(this.r) * 0.25;
this.yvel += Math.sin(this.r) * 0.25; this.yvel += Math.sin(this.r) * 0.25;
@ -64,14 +60,8 @@ class Grapple extends Projectile {
return []; return [];
} }
packFull() { packProjectileFull() {
return { return {};
type: 'grapple',
id: this.id,
source: this.source.id,
frame: this.frame,
delta: this.packDelta()
};
} }
} }

View file

@ -51,14 +51,8 @@ class Missile extends Projectile {
return []; return [];
} }
packFull() { packProjectileFull() {
return { return {};
type: 'missile',
id: this.id,
source: this.source.id,
frame: this.frame,
delta: this.packDelta()
};
} }
} }

View file

@ -8,7 +8,21 @@ class Projectile extends Body {
} }
connect() { connect() {
}
packTypeDelta() {
return [];
}
packProjectileFull() {
return {};
}
packTypeFull() {
let packet = this.packProjectileFull();
packet.source = this.source.id;
return packet;
} }
} }

View file

@ -4,13 +4,12 @@ const defaults = require('../traits/defaults.json');
const shipTraits = require('../traits/ships.json'); const shipTraits = require('../traits/ships.json');
const Body = require('./body.js'); const Body = require('./body.js');
const Mount = require('./turret/mount.js');
class Ship extends Body { class Ship extends Body {
constructor(world, pos, player, build) { constructor(world, pos, player, build) {
super(world);
build = build || defaults.spawnShip; build = build || defaults.spawnShip;
let traits = shipTraits[build.ship];
super(world, traits, build);
// Body data. // Body data.
this.x = pos.x || 0; this.x = pos.x || 0;
@ -23,19 +22,18 @@ class Ship extends Body {
this.grapple = false; this.grapple = false;
// Traits. // Traits.
let traits = shipTraits[this.class];
this.traits = traits; this.traits = traits;
this.frame = traits.frame; this.frame = traits.frame;
this.power = traits.power; this.power = traits.power;
this.size = traits.size; this.size = traits.size;
// Mounts // Delta interface.
traits.mounts.forEach((data, i) => { this.interface.order.push.apply(this.interface.order, [
let mount = new Mount(this, data); 'thrustForward',
this.mounts.push(mount); 'thrustLeft',
}); 'thrustRight'
]);
this.turrets = build.turrets || []; this.interface.type = 'ship';
this.thrust = { this.thrust = {
forward: 0, forward: 0,
@ -56,9 +54,9 @@ class Ship extends Body {
release: data[7] release: data[7]
}; };
this.thrust.forward = this.inputs.forward; this.thrust.forward = +this.inputs.forward;
this.thrust.left = this.inputs.left; this.thrust.left = +this.inputs.left;
this.thrust.right = this.inputs.right; this.thrust.right = +this.inputs.right;
if (this.inputs.missile) this.launchMissile(); if (this.inputs.missile) this.launchMissile();
if (this.inputs.grapple) { if (this.inputs.grapple) {
@ -100,22 +98,23 @@ class Ship extends Body {
packTypeDelta() { packTypeDelta() {
let t = this.thrust; let t = this.thrust;
return [t.forward, t.left, t.right];
return [t.forward, t.left, t.right, this.debug || false];
} }
packFull() { getTypeDeltaInterface() {
return [
'thrustForward',
'thrustLeft',
'thrustRight'
];
}
packTypeFull() {
return { return {
type: 'ship',
id: this.id,
team: this.player.team, team: this.player.team,
name: this.player.name, name: this.player.name,
frame: this.frame,
power: this.power, power: this.power,
mounts: this.mounts.map(m => m.packFull()), size: this.size
turrets: this.turrets.map(t => t.packFull()),
size: this.size,
delta: this.packDelta()
}; };
} }
} }

View file

@ -17,7 +17,9 @@ class Mount {
this.traversal = data.traversal ? { this.traversal = data.traversal ? {
cw: data.bounds[0], cw: data.bounds[0],
ccw: data.bounds[1] ccw: data.bounds[1]
} : false; } : 0;
this.updateDeltaInterface();
} }
destruct() { destruct() {
@ -25,11 +27,20 @@ class Mount {
this.fixture.destruct(); this.fixture.destruct();
} }
packDelta() {
return [this.traversal || 0];
}
updateDeltaInterface() {
this.deltaInterface = this.fixture ? ['traversal'] : [];
}
packFull() { packFull() {
return { return {
x: this.position.x, x: this.position.x,
y: this.position.y y: this.position.y,
} turret: this.turret ? this.turret.type : 0
};
} }
} }

View file

@ -11,12 +11,12 @@ class World {
this.physics = new Physics(); this.physics = new Physics();
this.spawner = new Spawner(this); this.spawner = new Spawner(this);
this.bodies = new Set(); this.bodies = new Set();
this.copulae = new Set();
this.structures = new Set();
this.asteroids = new Set(); this.asteroids = new Set();
this.copulae = new Set();
this.players = new Set();
this.projectiles = new Set(); this.projectiles = new Set();
this.ships = new Map(); this.ships = new Map();
this.players = new Set(); this.structures = new Set();
this.room = room; this.room = room;
this.tps = 0; this.tps = 0;
this.tpsCount = 0; this.tpsCount = 0;
@ -63,18 +63,18 @@ class World {
} }
addAsteroid(asteroid) { addAsteroid(asteroid) {
this.asteroids.add(asteroid);
this.addBody(asteroid); this.addBody(asteroid);
} }
addProjectile(projectile) { addProjectile(projectile) {
this.projectiles.add(projectile);
this.addBody(projectile); this.addBody(projectile);
projectile.connect(); projectile.connect();
} }
addBody(body) { addBody(body) {
this.bodies.add(body); this.bodies.add(body);
if (body.type == 'asteroid') this.asteroids.add(body);
if (body.type == 'structure') this.structures.add(body);
this.physics.createBody(body); this.physics.createBody(body);
this.room.broadcast('create', body.packFull()); this.room.broadcast('create', body.packFull());
} }
@ -85,8 +85,9 @@ class World {
this.room.broadcast('effect', copula.packFull()); this.room.broadcast('effect', copula.packFull());
} }
applyDelta(body, data) { applyDelta(data) {
this.players.forEach(player => player.delta[body] = data); data = data.map(v => +(v.toFixed(3)));
this.players.forEach(player => player.applyDelta(data));
} }
explosion(pos, power) { explosion(pos, power) {
@ -126,9 +127,9 @@ class World {
removeBody(body) { removeBody(body) {
body.destruct(); body.destruct();
this.bodies.delete(body); this.bodies.delete(body);
this.ships.delete(body);
this.structures.delete(body);
this.asteroids.delete(body); this.asteroids.delete(body);
this.structures.delete(body);
this.ships.delete(body);
this.projectiles.delete(body); this.projectiles.delete(body);
this.room.broadcast('destroy', body.id); this.room.broadcast('destroy', body.id);
} }
@ -143,15 +144,15 @@ class World {
} }
start() { start() {
this.interval = setInterval(_ => this.tick(this), 1000 / 60);
} }
stop() { stop() {
clearInterval(this.interval);
} }
tick(self) { tick() {
self.physics.step(); this.physics.step();
let tickBodies = (set, interval) => { let tickBodies = (set, interval) => {
set.forEach(body => { set.forEach(body => {
@ -161,9 +162,9 @@ class World {
}); });
}; };
tickBodies(self.ships, 1); tickBodies(this.ships, 1);
tickBodies(self.asteroids, 4); tickBodies(this.asteroids, 4);
tickBodies(self.projectiles, 1); tickBodies(this.projectiles, 1);
if (Date.now() - this.tpsStart > 5000) { if (Date.now() - this.tpsStart > 5000) {
this.tps = this.tpsCount / 5 | 0; this.tps = this.tpsCount / 5 | 0;

View file

@ -30,7 +30,6 @@ class Spawner {
yvel: ship.vel.y yvel: ship.vel.y
}; };
let missile = new Missile(this.world, pos, ship); let missile = new Missile(this.world, pos, ship);
this.world.addProjectile(missile);
return missile; return missile;
} }