mirror of
https://github.com/danbulant/flying-squid
synced 2026-06-11 18:41:31 +00:00
295 lines
No EOL
9.6 KiB
JavaScript
295 lines
No EOL
9.6 KiB
JavaScript
var Entity=require("../entity");
|
|
var Vec3 = require("vec3").Vec3;
|
|
var entitiesByName=require("minecraft-data")(require("../version")).entitiesByName;
|
|
|
|
var path = require('path');
|
|
var requireIndex = require('requireindex');
|
|
var plugins = requireIndex(path.join(__dirname,'..', 'plugins'));
|
|
|
|
module.exports.server=function(serv,options) {
|
|
|
|
serv.initEntity = (type, entityType, world, position) => {
|
|
serv.entityMaxId++;
|
|
var entity = new Entity(serv.entityMaxId);
|
|
|
|
Object.keys(plugins)
|
|
.filter(pluginName => plugins[pluginName].entity!=undefined)
|
|
.forEach(pluginName => plugins[pluginName].entity(entity, serv, options));
|
|
|
|
entity.initEntity(type, entityType, world, position);
|
|
|
|
serv.emit("newEntity",entity);
|
|
|
|
return entity;
|
|
};
|
|
|
|
serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0}={}) => {
|
|
var object = serv.initEntity('object', type, world, position.scaled(32).floored());
|
|
object.data = data;
|
|
object.velocity = velocity.scaled(32).floored();
|
|
object.pitch = pitch;
|
|
object.yaw = yaw;
|
|
object.gravity = new Vec3(0, -20*32, 0);
|
|
object.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
|
|
object.friction = new Vec3(15*32, 0, 15*32);
|
|
object.size = new Vec3(0.25*32, 0.25*32, 0.25*32); // Hardcoded, will be dependent on type!
|
|
object.deathTime = 60*1000; // 60 seconds
|
|
object.pickupTime = 200;
|
|
object.itemId = itemId;
|
|
object.itemDamage = itemDamage;
|
|
|
|
object.updateAndSpawn();
|
|
};
|
|
|
|
serv.spawnMob = (type, world, position, {pitch=0,yaw=0,headPitch=0,velocity=new Vec3(0,0,0),metadata=[]}={}) => {
|
|
var mob = serv.initEntity('mob', type, world, position.scaled(32).floored());
|
|
mob.velocity = velocity.scaled(32).floored();
|
|
mob.pitch = pitch;
|
|
mob.headPitch = headPitch;
|
|
mob.yaw = yaw;
|
|
mob.gravity = new Vec3(0, -20*32, 0);
|
|
mob.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
|
|
mob.friction = new Vec3(15*32, 0, 15*32);
|
|
mob.size = new Vec3(0.75, 1.75, 0.75);
|
|
mob.health = 20;
|
|
mob.metadata = metadata;
|
|
|
|
mob.updateAndSpawn();
|
|
};
|
|
|
|
serv.destroyEntity = entity => {
|
|
entity._writeOthersNearby('entity_destroy', {
|
|
entityIds: [entity.id]
|
|
});
|
|
delete serv.entities[entity.id];
|
|
};
|
|
|
|
serv.on('tick', function(delta) {
|
|
Promise.all(
|
|
Object.keys(serv.entities).map(async (id) => {
|
|
var entity = serv.entities[id];
|
|
if (entity.deathTime && Date.now() - entity.bornTime >= entity.deathTime) {
|
|
entity.destroy();
|
|
return;
|
|
} else if (entity.pickupTime && Date.now() - entity.bornTime >= entity.pickupTime) {
|
|
var players = serv.getNearby({
|
|
world: entity.world,
|
|
position: entity.position,
|
|
radius: 1.5*32 // Seems good for now
|
|
});
|
|
if (players.length) {
|
|
players[0].collect(entity);
|
|
entity.destroy();
|
|
}
|
|
}
|
|
if (!entity.velocity || !entity.size) return;
|
|
var oldPosAndOnGround = await entity.calculatePhysics(delta);
|
|
if (!oldPosAndOnGround.oldPos.equals(new Vec3(0,0,0)))
|
|
if (entity.type == 'mob') entity.sendPosition(oldPosAndOnGround);
|
|
})
|
|
).catch((err)=> setTimeout(() => {throw err;},0));
|
|
});
|
|
};
|
|
|
|
module.exports.player=function(player,serv){
|
|
player.commands.add({
|
|
base: 'spawn',
|
|
info: 'Spawn a mob',
|
|
usage: '/spawn <entity_id>',
|
|
parse(str) {
|
|
var results=str.match(/(\d+)/);
|
|
if (!results) return false;
|
|
return {
|
|
id: parseInt(results[1])
|
|
}
|
|
},
|
|
action({id}) {
|
|
serv.spawnMob(id, player.world, player.position.scaled(1/32), {
|
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
|
|
});
|
|
}
|
|
});
|
|
|
|
player.commands.add({
|
|
base: 'spawnObject',
|
|
info: 'Spawn an object',
|
|
usage: '/spawnObject <entity_id>',
|
|
parse(str) {
|
|
var results=str.match(/(\d+)/);
|
|
if (!results) return false;
|
|
return {
|
|
id: parseInt(results[1])
|
|
}
|
|
},
|
|
action({id}) {
|
|
serv.spawnObject(id, player.world, player.position.scaled(1/32), {
|
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
|
|
});
|
|
}
|
|
});
|
|
|
|
player.commands.add({
|
|
base: 'summon',
|
|
info: 'Summon an entity',
|
|
usage: '/summon <entity_name>',
|
|
action(name) {
|
|
var entity=entitiesByName[name];
|
|
if(!entity) {
|
|
player.chat("No entity named "+name);
|
|
return;
|
|
}
|
|
serv.spawnMob(entity.id, player.world, player.position.scaled(1/32), {
|
|
velocity: Vec3((Math.random() - 0.5) * 10, Math.random()*10 + 10, (Math.random() - 0.5) * 10)
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
module.exports.entity=function(entity,serv){
|
|
|
|
entity.initEntity=(type, entityType, world, position)=>{
|
|
entity.type = type;
|
|
entity.spawnPacketName = '';
|
|
entity.entityType = entityType;
|
|
entity.world = world;
|
|
entity.position = position;
|
|
entity.lastPositionPlayersUpdated = entity.position.clone();
|
|
entity.nearbyEntities = [];
|
|
entity.viewDistance = 150;
|
|
|
|
entity.bornTime = Date.now();
|
|
serv.entities[entity.id] = entity;
|
|
|
|
if (entity.type == 'player') entity.spawnPacketName = 'named_entity_spawn';
|
|
else if (entity.type == 'object') entity.spawnPacketName = 'spawn_entity';
|
|
else if (entity.type == 'mob') entity.spawnPacketName = 'spawn_entity_living';
|
|
};
|
|
|
|
|
|
entity.on("positionChanged",() => {
|
|
if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32)
|
|
entity.updateAndSpawn();
|
|
});
|
|
|
|
entity.sendMetadata = (data) => {
|
|
entity._writeOthersNearby('entity_metadata', {
|
|
entityId: entity.id,
|
|
metadata: data
|
|
});
|
|
};
|
|
|
|
entity.setAndUpdateMetadata = (data) => {
|
|
entity.metadata = data;
|
|
entity.sendMetadata(data);
|
|
}
|
|
|
|
entity.destroy = () => {
|
|
serv.destroyEntity(entity);
|
|
};
|
|
|
|
entity.getSpawnPacket = () => {
|
|
var scaledVelocity = entity.velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick
|
|
if (entity.type == 'player') {
|
|
return {
|
|
entityId: entity.id,
|
|
playerUUID: entity._client.uuid,
|
|
x: entity.position.x,
|
|
y: entity.position.y,
|
|
z: entity.position.z,
|
|
yaw: entity.yaw,
|
|
pitch: entity.pitch,
|
|
currentItem: 0,
|
|
metadata: entity.metadata
|
|
}
|
|
} else if (entity.type == 'object') {
|
|
return {
|
|
entityId: entity.id,
|
|
type: entity.entityType,
|
|
x: entity.position.x,
|
|
y: entity.position.y,
|
|
z: entity.position.z,
|
|
pitch: entity.pitch,
|
|
yaw: entity.yaw,
|
|
objectData: {
|
|
intField: entity.data,
|
|
velocityX: scaledVelocity.x,
|
|
velocityY: scaledVelocity.y,
|
|
velocityZ: scaledVelocity.z
|
|
}
|
|
}
|
|
} else if (entity.type == 'mob') {
|
|
return {
|
|
entityId: entity.id,
|
|
type: entity.entityType,
|
|
x: entity.position.x,
|
|
y: entity.position.y,
|
|
z: entity.position.z,
|
|
yaw: entity.yaw,
|
|
pitch: entity.pitch,
|
|
headPitch: entity.headPitch,
|
|
velocityX: scaledVelocity.x,
|
|
velocityY: scaledVelocity.y,
|
|
velocityZ: scaledVelocity.z,
|
|
metadata: entity.metadata
|
|
}
|
|
}
|
|
};
|
|
|
|
entity.updateAndSpawn = () => {
|
|
var updatedEntities=entity.getNearby();
|
|
var entitiesToAdd=updatedEntities.filter(e => entity.nearbyEntities.indexOf(e)==-1);
|
|
var entitiesToRemove=entity.nearbyEntities.filter(e => updatedEntities.indexOf(e)==-1);
|
|
if (entity.type == 'player') {
|
|
entity.despawnEntities(entitiesToRemove);
|
|
entitiesToAdd.forEach(entity.spawnEntity);
|
|
}
|
|
entity.lastPositionPlayersUpdated=entity.position.clone();
|
|
|
|
var playersToAdd = entitiesToAdd.filter(e => e.type == 'player');
|
|
var playersToRemove = entitiesToRemove.filter(e => e.type == 'player');
|
|
|
|
playersToRemove.forEach(p => p.despawnEntities([entity]));
|
|
playersToRemove.forEach(p => p.nearbyEntities=p.getNearby());
|
|
playersToAdd.forEach(p => p.spawnEntity(entity));
|
|
playersToAdd.forEach(p => p.nearbyEntities=p.getNearby());
|
|
|
|
entity.nearbyEntities=updatedEntities;
|
|
};
|
|
|
|
entity.collect = (collectEntity) => {
|
|
if (entity.type != 'player') serv.emit('error', 'Non-player entity (ttype ' + entity.type + ') cannot collect another entity');
|
|
else {
|
|
collectEntity._writeOthersNearby('collect', {
|
|
collectedEntityId: collectEntity.id,
|
|
collectorEntityId: entity.id
|
|
});
|
|
entity.playSoundAtSelf('random.pop');
|
|
}
|
|
}
|
|
|
|
entity.sendVelocity = (vel, maxVel) => {
|
|
var velocity = vel.scaled(32).floored(); // Make fixed point
|
|
var maxVelocity = maxVel.scaled(32).floored();
|
|
var scaledVelocity = velocity.scaled(8000/32/20).floored(); // from fixed-position/second to unit => 1/8000 blocks per tick
|
|
entity._writeOthersNearby('entity_velocity', {
|
|
entityId: entity.id,
|
|
velocityX: scaledVelocity.x,
|
|
velocityY: scaledVelocity.y,
|
|
velocityZ: scaledVelocity.z
|
|
});
|
|
if (entity.type != 'player') {
|
|
if (maxVelocity) entity.velocity = addVelocityWithMax(entity.velocity, velocity, maxVelocity);
|
|
else entity.velocity.add(velocity);
|
|
}
|
|
}
|
|
function addVelocityWithMax(current, newVel, max) {
|
|
var x, y, z;
|
|
if (current.x > max.x || current.x < -max.x) x = current.x;
|
|
else x = Math.max(-max.x, Math.min(max.x, current.x + newVel.x));
|
|
if (current.y > max.y || current.y < -max.y) y = current.y;
|
|
else y = Math.max(-max.y, Math.min(max.y, current.y + newVel.y));
|
|
if (current.z > max.z || current.z < -max.z) z = current.z;
|
|
else z = Math.max(-max.z, Math.min(max.z, current.z + newVel.z));
|
|
return new Vec3(x, y, z);
|
|
}
|
|
}; |