mirror of
https://github.com/danbulant/flying-squid
synced 2026-06-24 17:21:43 +00:00
commit
5bff660bbe
20 changed files with 752 additions and 217 deletions
2
TODO.md
2
TODO.md
|
|
@ -20,11 +20,11 @@ This is a list that will keep the developers and the community organized!
|
||||||
- [x] Other dimensions
|
- [x] Other dimensions
|
||||||
- [x] Block dropping
|
- [x] Block dropping
|
||||||
- [x] Entity basics
|
- [x] Entity basics
|
||||||
|
- [x] Plugin System
|
||||||
|
|
||||||
### To-do
|
### To-do
|
||||||
#### Priority
|
#### Priority
|
||||||
- [ ] Inventories (saving the blocks players get)
|
- [ ] Inventories (saving the blocks players get)
|
||||||
- [ ] Plugin System
|
|
||||||
- [ ] Crafting and Smelting
|
- [ ] Crafting and Smelting
|
||||||
- [ ] Add in cluster functionality
|
- [ ] Add in cluster functionality
|
||||||
|
|
||||||
|
|
|
||||||
476
doc/api.md
476
doc/api.md
|
|
@ -19,6 +19,7 @@
|
||||||
- [serv.time](#servtime)
|
- [serv.time](#servtime)
|
||||||
- [serv.tickCount](#servtickcount)
|
- [serv.tickCount](#servtickcount)
|
||||||
- [serv.doDaylightCycle](#servdodaylightcycle)
|
- [serv.doDaylightCycle](#servdodaylightcycle)
|
||||||
|
- [serv.plugins](#servplugins)
|
||||||
- [Events](#events)
|
- [Events](#events)
|
||||||
- ["error" (error)](#error-error)
|
- ["error" (error)](#error-error)
|
||||||
- ["clientError" (client,error)](#clienterror-clienterror)
|
- ["clientError" (client,error)](#clienterror-clienterror)
|
||||||
|
|
@ -48,21 +49,72 @@
|
||||||
- [server._writeAll(packetName, packetFields)](#server_writeallpacketname-packetfields)
|
- [server._writeAll(packetName, packetFields)](#server_writeallpacketname-packetfields)
|
||||||
- [server._writeArray(packetName, packetFields, playerArray)](#server_writearraypacketname-packetfields-playerarray)
|
- [server._writeArray(packetName, packetFields, playerArray)](#server_writearraypacketname-packetfields-playerarray)
|
||||||
- [server._writeNearby(packetName, packetFields, loc)](#server_writenearbypacketname-packetfields-loc)
|
- [server._writeNearby(packetName, packetFields, loc)](#server_writenearbypacketname-packetfields-loc)
|
||||||
- [Player](#player)
|
- [Entity](#entity-1)
|
||||||
- [Properties](#properties-1)
|
- [Properties](#properties-1)
|
||||||
- [player.entity](#playerentity)
|
- [entity.id](#entityid)
|
||||||
|
- [entity.position](#entityposition)
|
||||||
|
- [entity.world](#entityworld)
|
||||||
|
- [entity.type](#entitytype)
|
||||||
|
- [entity.entityType](#entityentitytype)
|
||||||
|
- [entity.nearbyEntities](#entitynearbyentities)
|
||||||
|
- [entity.viewDistance](#entityviewdistance)
|
||||||
|
- [entity.health](#entityhealth)
|
||||||
|
- [entity.pitch](#entitypitch)
|
||||||
|
- [entity.headPitch](#entityheadpitch)
|
||||||
|
- [entity.yaw](#entityyaw)
|
||||||
|
- [entity.gravity](#entitygravity)
|
||||||
|
- [entity.terminalvelocity](#entityterminalvelocity)
|
||||||
|
- [entity.friction](#entityfriction)
|
||||||
|
- [entity.size](#entitysize)
|
||||||
|
- [entity.deathTime](#entitydeathtime)
|
||||||
|
- [entity.pickupTime](#entitypickuptime)
|
||||||
|
- [entity.bornTime](#entityborntime)
|
||||||
|
- [entity.itemId](#entityitemid)
|
||||||
|
- [entity.itemDamage](#entityitemdamage)
|
||||||
|
- [entity.metadata](#entitymetadata)
|
||||||
|
- [entity.nearbyEntities](#entitynearbyentities-1)
|
||||||
|
- [Events](#events-1)
|
||||||
|
- [Behaviors](#behaviors)
|
||||||
|
- [FORMAT](#format)
|
||||||
|
- ["move"](#move)
|
||||||
|
- [Methods](#methods-1)
|
||||||
|
- [entity.getData(pluginName)](#entitygetdatapluginname)
|
||||||
|
- [entity.getOthers()](#entitygetothers)
|
||||||
|
- [entity.getOtherPlayers()](#entitygetotherplayers)
|
||||||
|
- [entity.getNearby()](#entitygetnearby)
|
||||||
|
- [entity.getNearbyPlayers()](#entitygetnearbyplayers)
|
||||||
|
- [entity.nearbyPlayers()](#entitynearbyplayers)
|
||||||
|
- [Low level Methods](#low-level-methods)
|
||||||
|
- [entity._writeOthers(packetName, packetFields)](#entity_writeotherspacketname-packetfields)
|
||||||
|
- [entity._writeOthersNearby(packetName, packetFields)](#entity_writeothersnearbypacketname-packetfields)
|
||||||
|
- [Player](#player)
|
||||||
|
- [Properties](#properties-2)
|
||||||
- [player.username](#playerusername)
|
- [player.username](#playerusername)
|
||||||
- [player.view](#playerview)
|
- [player.view](#playerview)
|
||||||
- [player.world](#playerworld)
|
- [Events](#events-2)
|
||||||
- [player.nearbyPlayers](#playernearbyplayers)
|
|
||||||
- [Events](#events-1)
|
|
||||||
- ["connected"](#connected)
|
- ["connected"](#connected)
|
||||||
- ["spawned"](#spawned)
|
- ["spawned"](#spawned)
|
||||||
- ["disconnected"](#disconnected)
|
- ["disconnected"](#disconnected)
|
||||||
- ["chat" (message)](#chat-message)
|
- ["chat" (message)](#chat-message)
|
||||||
- ["kicked" (kicker,reason)](#kicked-kickerreason)
|
- ["kicked" (kicker,reason)](#kicked-kickerreason)
|
||||||
- ["positionChanged"](#positionchanged)
|
- ["positionChanged"](#positionchanged)
|
||||||
- [Methods](#methods-1)
|
- [Behaviors](#behaviors-1)
|
||||||
|
- ["move"](#move-1)
|
||||||
|
- ["look"](#look)
|
||||||
|
- ["chat"](#chat)
|
||||||
|
- ["command"](#command)
|
||||||
|
- ["punch"](#punch)
|
||||||
|
- ["sendBlock"](#sendblock)
|
||||||
|
- ["sendChunk"](#sendchunk)
|
||||||
|
- ["dig"](#dig)
|
||||||
|
- ["dug"](#dug)
|
||||||
|
- ["cancelDig"](#canceldig)
|
||||||
|
- ["forceCancelDig"](#forcecanceldig)
|
||||||
|
- ["breakAnimation"](#breakanimation)
|
||||||
|
- ["placeBlock"](#placeblock)
|
||||||
|
- ["attack"](#attack)
|
||||||
|
- ["requestRespawn"](#requestrespawn)
|
||||||
|
- [Methods](#methods-2)
|
||||||
- [player.login()](#playerlogin)
|
- [player.login()](#playerlogin)
|
||||||
- [player.ban(reason)](#playerbanreason)
|
- [player.ban(reason)](#playerbanreason)
|
||||||
- [player.kick(reason)](#playerkickreason)
|
- [player.kick(reason)](#playerkickreason)
|
||||||
|
|
@ -83,8 +135,6 @@
|
||||||
- [Low level properties](#low-level-properties)
|
- [Low level properties](#low-level-properties)
|
||||||
- [player._client](#player_client)
|
- [player._client](#player_client)
|
||||||
- [Low level methods](#low-level-methods-1)
|
- [Low level methods](#low-level-methods-1)
|
||||||
- [player._writeOthers(packetName, packetFields)](#player_writeotherspacketname-packetfields)
|
|
||||||
- [player._writeOthersNearby(packetName, packetFields)](#player_writeothersnearbypacketname-packetfields)
|
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
|
@ -159,6 +209,10 @@ Best to use with modulo (e.g. Something every 10 seconds is `serv.tickCount % 20
|
||||||
|
|
||||||
Default `true`. If false, time will not automatically pass.
|
Default `true`. If false, time will not automatically pass.
|
||||||
|
|
||||||
|
#### serv.plugins
|
||||||
|
|
||||||
|
List of all plugins. Use serv.plugins[pluginName] to get a plugin's object and data.
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
#### "error" (error)
|
#### "error" (error)
|
||||||
|
|
@ -293,13 +347,227 @@ Writes packet to every player in playerArray
|
||||||
|
|
||||||
Writes packet to all players within distance of loc. loc has the same paramater as loc in server.getNearby()
|
Writes packet to all players within distance of loc. loc has the same paramater as loc in server.getNearby()
|
||||||
|
|
||||||
## Player
|
## Entity
|
||||||
|
|
||||||
|
Players are a type of entity, so they will have most of the attributes and methods
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
#### player.entity
|
#### entity.id
|
||||||
|
|
||||||
The entity of the player, of type `Flying-squid.Entity`
|
ID of entity on server
|
||||||
|
|
||||||
|
#### entity.position
|
||||||
|
|
||||||
|
Current position (currently in fixed position (x32 what you'd expect) so do entity.position.scaled(1/32) to get normal position)
|
||||||
|
|
||||||
|
#### entity.world
|
||||||
|
|
||||||
|
World object entity is in
|
||||||
|
|
||||||
|
#### entity.type
|
||||||
|
|
||||||
|
Either "player", "mob", or "object" (currently)
|
||||||
|
|
||||||
|
#### entity.entityType
|
||||||
|
|
||||||
|
Sub-category of entity. For mobs, this is which mob (Zombie/Skeleton, etc). For objects, this is which object (Arrow/Dropped item, etc)
|
||||||
|
|
||||||
|
#### entity.nearbyEntities
|
||||||
|
|
||||||
|
Nearby entities to this entity
|
||||||
|
|
||||||
|
#### entity.viewDistance
|
||||||
|
|
||||||
|
How far away entities are loaded/unloaded (used for players ATM)
|
||||||
|
|
||||||
|
#### entity.health
|
||||||
|
|
||||||
|
How many half-hearts an entity has of health (e.g. Player has 20). Not really used for objects, only players and mobs.
|
||||||
|
|
||||||
|
#### entity.pitch
|
||||||
|
|
||||||
|
Pitch of entity (rotation sideways)
|
||||||
|
|
||||||
|
#### entity.headPitch
|
||||||
|
|
||||||
|
Pitch of entity's head
|
||||||
|
|
||||||
|
#### entity.yaw
|
||||||
|
|
||||||
|
Yaw of entity (rotation looking up and down)
|
||||||
|
|
||||||
|
#### entity.gravity
|
||||||
|
|
||||||
|
Gravity of entity (non-players) to calculate physics.
|
||||||
|
|
||||||
|
#### entity.terminalvelocity
|
||||||
|
|
||||||
|
Only applies to gravity, really. You can still apply a velocity larger than terminal velocity.
|
||||||
|
|
||||||
|
#### entity.friction
|
||||||
|
|
||||||
|
Decreases velocity when touching blocks
|
||||||
|
|
||||||
|
#### entity.size
|
||||||
|
|
||||||
|
Used to calculate collisions for server-side entities
|
||||||
|
|
||||||
|
#### entity.deathTime
|
||||||
|
|
||||||
|
How much time before an entity despawns (in ms)
|
||||||
|
|
||||||
|
#### entity.pickupTime
|
||||||
|
|
||||||
|
How long before an entity can be picked up (in ms)
|
||||||
|
|
||||||
|
#### entity.bornTime
|
||||||
|
|
||||||
|
When an entity was born. Used with pickupTime and deathTime (time in epoch)
|
||||||
|
|
||||||
|
#### entity.itemId
|
||||||
|
|
||||||
|
If a block drop, what item id
|
||||||
|
|
||||||
|
#### entity.itemDamage
|
||||||
|
|
||||||
|
If a block drop, what item damage
|
||||||
|
|
||||||
|
#### entity.metadata
|
||||||
|
|
||||||
|
Metadata for the entity (not like block metadata/damage). Contains stuff like NBT.
|
||||||
|
|
||||||
|
#### entity.nearbyEntities
|
||||||
|
|
||||||
|
List of entities that the entity believes is nearby.
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Behaviors
|
||||||
|
|
||||||
|
Behaviors are very interesting. Let me explain to you how they work:
|
||||||
|
|
||||||
|
Behaviors are a special type of event. They are editable and allow defaults to be cancellable making the powerful
|
||||||
|
for plugins to take control of and interact with each other. Three different events get called
|
||||||
|
for a behavior:
|
||||||
|
- EVENTNAME_cancel
|
||||||
|
- EVENTNAME
|
||||||
|
- EVENTNAME_done
|
||||||
|
|
||||||
|
EVENTNAME_cancel passses the paramaters `data` (object of all info about behavior. Changing the data could have effects on outcome) and `cancel`, a function. This event is run before the default action. If `cancel()` is called, it will cancel the default action. More on this later.
|
||||||
|
|
||||||
|
EVENTNAME passes `data` as well as `cancelled` so plugins can check if the default behavior has been cancelled. This is event is run
|
||||||
|
before the default action.
|
||||||
|
|
||||||
|
EVENTNAME_done passes `data` and `cancelled`. This event is run before the default action.
|
||||||
|
|
||||||
|
Example: One plugin wants to cancel a player's movement while another wants to say "HI" when they move
|
||||||
|
|
||||||
|
Plugin A:
|
||||||
|
```js
|
||||||
|
player.on('move_cancel', ({position}, cancel) => {
|
||||||
|
cancel(); // If player tries to move, shoots them back where they came from
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Plugin B:
|
||||||
|
```js
|
||||||
|
player.on('move', ({position}, cancelled) => {
|
||||||
|
if (!cancelled) player.chat('HI!');
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
When a player normally moves, the server saves their position and sends it to all clients. Therefore, if a "move" behavior was truly cancelled,
|
||||||
|
the player would be able to move freely while the server and other players would see the player stationary. This doesn't happen because
|
||||||
|
behaviors can have "default cancel functions". In the case of a player's "move", the default cancel function sends them back where they
|
||||||
|
came from. To prevent this from happening, use the "preventDefaultCancel" paramater: cancel(false);
|
||||||
|
|
||||||
|
Plugin C
|
||||||
|
```js
|
||||||
|
player.on('move_cancel', ({position}, cancel) => {
|
||||||
|
cancel(false); // Doesn't teleport player back
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
If we keep Plugin B and replace Plugin A with Plugin C, we'll see that the player can move freely but will not recieve the
|
||||||
|
word "HI" and other players will be unable to see their movements.
|
||||||
|
|
||||||
|
Finally, there is hidden cancel. This is the second paramater in cancel, and allows plugins to hide the fact that they cancelled
|
||||||
|
the default action from other plugins. It's best not to use this, but I know somebody will someday need this.
|
||||||
|
|
||||||
|
Plugin D
|
||||||
|
```js
|
||||||
|
player.on('move_cancel', ({position}, cancel) => {
|
||||||
|
cancel(false, true); // Player doesn't teleport back and now "cancelled" will be false
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Using Plugin B and D together, the player will be able to move freely and will be spammed with "HI", however the server will not store
|
||||||
|
their position and other players will not see the player move.
|
||||||
|
|
||||||
|
#### FORMAT
|
||||||
|
|
||||||
|
Defition of behavior.
|
||||||
|
- var1: Variable with value, can be changed (default: defaultValue)
|
||||||
|
- var2 (u): Variable with value. You can change it however it will not have any effect on the defautl action (and could screw with other plugins, watch out!). U stands for unused
|
||||||
|
|
||||||
|
Default: What happens if this isn't cancelled.
|
||||||
|
|
||||||
|
Cancelled: What happens if this is cancelled and preventDefaultCancel is still false.
|
||||||
|
|
||||||
|
#### "move"
|
||||||
|
|
||||||
|
Emitted when server calculates new position for the entity (DOES NOT APPLY TO PLAYER!)
|
||||||
|
- old (u): Where the entity came from
|
||||||
|
- onGround (u): If the entity is on the ground
|
||||||
|
|
||||||
|
Default: Send entity relative-move or teleport packets to all nearby players
|
||||||
|
|
||||||
|
Cancelled: Set entity position to old position
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
#### entity.getData(pluginName)
|
||||||
|
|
||||||
|
Gets object that stores data, personalized per plugin. Returns null if plugin does not exist.
|
||||||
|
|
||||||
|
Shortcut for: entity.pluginData[pluginName];
|
||||||
|
|
||||||
|
#### entity.getOthers()
|
||||||
|
|
||||||
|
Get every other entity other than self
|
||||||
|
|
||||||
|
#### entity.getOtherPlayers()
|
||||||
|
|
||||||
|
Gets every player other than self (all players if entity is not a player)
|
||||||
|
|
||||||
|
#### entity.getNearby()
|
||||||
|
|
||||||
|
Gets all entities nearby (within entity.viewDistance)
|
||||||
|
|
||||||
|
#### entity.getNearbyPlayers()
|
||||||
|
|
||||||
|
Gets all nearby players regardless of what client thinks
|
||||||
|
|
||||||
|
#### entity.nearbyPlayers()
|
||||||
|
|
||||||
|
Gets all nearby players that client can see
|
||||||
|
|
||||||
|
### Low level Methods
|
||||||
|
|
||||||
|
#### entity._writeOthers(packetName, packetFields)
|
||||||
|
|
||||||
|
Writes to all other players on server
|
||||||
|
|
||||||
|
#### entity._writeOthersNearby(packetName, packetFields)
|
||||||
|
|
||||||
|
Writes to all players within viewDistance
|
||||||
|
|
||||||
|
## Player
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
#### player.username
|
#### player.username
|
||||||
|
|
||||||
|
|
@ -309,14 +577,6 @@ The username of the player
|
||||||
|
|
||||||
The view size of the player, for example 8 for 16x16
|
The view size of the player, for example 8 for 16x16
|
||||||
|
|
||||||
#### player.world
|
|
||||||
|
|
||||||
The world which the player is in.
|
|
||||||
|
|
||||||
#### player.nearbyPlayers
|
|
||||||
|
|
||||||
Nearby players.
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
#### "connected"
|
#### "connected"
|
||||||
|
|
@ -343,6 +603,176 @@ Fires when the player says `message`.
|
||||||
|
|
||||||
fires when the position changes in small amounts (walking, running, or flying)
|
fires when the position changes in small amounts (walking, running, or flying)
|
||||||
|
|
||||||
|
### Behaviors
|
||||||
|
|
||||||
|
See entity "Behaviors" for more info
|
||||||
|
|
||||||
|
#### "move"
|
||||||
|
|
||||||
|
When player tries to move
|
||||||
|
- position (u): New position player is trying to move to
|
||||||
|
- onGround (u): Whether player thinks they're on the ground or not
|
||||||
|
|
||||||
|
Default: Save position/onGround and write to all nearby players
|
||||||
|
|
||||||
|
Cancelled: Snap back to old position
|
||||||
|
|
||||||
|
#### "look"
|
||||||
|
|
||||||
|
When player tries to look somewhere
|
||||||
|
- yaw (u): New yaw player is looking
|
||||||
|
- pitch (u): New pitch player is looking
|
||||||
|
- onGround (u): If player thinks they're on the ground
|
||||||
|
|
||||||
|
Default: Save look directions, send to all nearby players
|
||||||
|
|
||||||
|
Cancelled: Snap their view back to old yaw and pitch
|
||||||
|
|
||||||
|
#### "chat"
|
||||||
|
|
||||||
|
Emitted when player tries to say something (unless they're message starts with /, then refer to "command")
|
||||||
|
- message (u): Message player sent
|
||||||
|
- broadcastMessage: What is put in server chat (Default: <username> message)
|
||||||
|
|
||||||
|
Default: Broadcasts to server their message
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "command"
|
||||||
|
|
||||||
|
Emitted when player starts their message with a slash
|
||||||
|
- command: Their commands (excludes the slash)
|
||||||
|
|
||||||
|
Default: Handle command by command system
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "punch"
|
||||||
|
|
||||||
|
When player tries to punch nothing
|
||||||
|
|
||||||
|
Default: Send punch animation to nearby players
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "sendBlock"
|
||||||
|
|
||||||
|
Emitted when sending a block to a player (block changed). This is separate for every player, cancelling this for one player causes ghost blocks!
|
||||||
|
- position: Position of the block
|
||||||
|
- id: ID of the block
|
||||||
|
- data: Metadata of the block
|
||||||
|
|
||||||
|
Default: Send block change to player.
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "sendChunk"
|
||||||
|
|
||||||
|
Emitted when sending a chunk to a player (loading it in)
|
||||||
|
- x: Chunk X
|
||||||
|
- z: Chunk Z
|
||||||
|
- chunk: Chunk data
|
||||||
|
|
||||||
|
Default: Continue sending chunk to client
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "dig"
|
||||||
|
|
||||||
|
Emitted when any player STARTS digging (i.e. survival only)
|
||||||
|
- position: Position of block being mined
|
||||||
|
- block (u): Block being mined
|
||||||
|
|
||||||
|
Default: Allow player to start mining block, send changes in break animation to other players
|
||||||
|
|
||||||
|
Cancelled: Stop them from digging
|
||||||
|
|
||||||
|
#### "dug"
|
||||||
|
|
||||||
|
Emitted when a player finishes digging something (or a player in creative breaks a block)
|
||||||
|
- position: Position of block dug
|
||||||
|
- block (u): Block dug
|
||||||
|
- dropBlock: Should it drop a block object (Default: false in creative, otherwise true)
|
||||||
|
- blockDropPosition: Where block is dropped (Default: center of block)
|
||||||
|
- blockDropWorld: World block is dropped in (Default is the world the player/block is in)
|
||||||
|
- blockDropVelocity: The velocity the block has when dropped (Default: random)
|
||||||
|
- blockDropId: ID of the block dropped
|
||||||
|
- blockDropDamage: Damage of the block dropped
|
||||||
|
- blockDropPickup: Time before user can pick up the block (Default: 0.5 seconds)
|
||||||
|
- blockDropDeath: Time before item despawns (Default: 5 minutes)
|
||||||
|
|
||||||
|
Default: Save new block as air, sends to all nearby players
|
||||||
|
|
||||||
|
Cancelled: Send to player the block that was there
|
||||||
|
|
||||||
|
#### "cancelDig"
|
||||||
|
|
||||||
|
Emitted when a player cancels digging in the middle (i.e. survival only)
|
||||||
|
- position: Position of block that was being mined
|
||||||
|
- block (u): Block that was being mined
|
||||||
|
|
||||||
|
Default: Stop animation for all players, save stop digging
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "forceCancelDig"
|
||||||
|
|
||||||
|
Emitted when the server cancels a dig (currently only happens if the player mines too fast)
|
||||||
|
- stop: Whether the digging should be cancelled because they mined too fast (Default: true)
|
||||||
|
- start (u): Time mining started
|
||||||
|
- time (u): How long the player has been mining
|
||||||
|
|
||||||
|
##### "breakAnimation"
|
||||||
|
|
||||||
|
Emitted when the server believes the break animation should increase (not sent by client!)
|
||||||
|
- position: Position of block being updated
|
||||||
|
- state: New state being changed to
|
||||||
|
- lastState (u): Last state of block
|
||||||
|
- start (u): When mining started
|
||||||
|
- timePassed (u): How long between start and now
|
||||||
|
|
||||||
|
Default: Send animation to everyone
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "placeBlock"
|
||||||
|
|
||||||
|
Emitted when a player places a block
|
||||||
|
- position: Position they're attempting to place the block
|
||||||
|
- id: Id of block being placed
|
||||||
|
- damage: Data of block being placed
|
||||||
|
- reference (u): Reference block that was placed on
|
||||||
|
- direction (u): Direction vector from reference to position
|
||||||
|
- playSound: Which sound to play (Default: true)
|
||||||
|
- sound: Sound to play (Default: default sound for that material)
|
||||||
|
|
||||||
|
Default: Place block for server and nearby players
|
||||||
|
|
||||||
|
Cancelled: Replace block with old block for player
|
||||||
|
|
||||||
|
#### "attack"
|
||||||
|
|
||||||
|
Emitted when a player attacks an entity
|
||||||
|
- attackedEntity: Entity being attacked
|
||||||
|
- playSound: Play sound (Default: true)
|
||||||
|
- sound: Sound to play (default is game.player.hurt)
|
||||||
|
- damage: Damage to deal (default is based off player's weapon, player's potions, attackEntity's potions, and attackedEntity armor)
|
||||||
|
- velocity: Which way should attackedEntity move when hit
|
||||||
|
- maxVelocity: maxVelocity from consecutive hits
|
||||||
|
- animation: Play death/hit animation
|
||||||
|
|
||||||
|
Default: Damage entity, play sound, send velocity, play animation for death/hit
|
||||||
|
|
||||||
|
Cancelled: Nothing
|
||||||
|
|
||||||
|
#### "requestRespawn"
|
||||||
|
|
||||||
|
Emitted when a player tries to respawn
|
||||||
|
|
||||||
|
Default: Let them respawn
|
||||||
|
|
||||||
|
Cancelled: Nothing. You monster.
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
#### player.login()
|
#### player.login()
|
||||||
|
|
@ -430,10 +860,4 @@ The internal implementation to communicate with a client
|
||||||
|
|
||||||
### Low level methods
|
### Low level methods
|
||||||
|
|
||||||
#### player._writeOthers(packetName, packetFields)
|
Same as entity
|
||||||
|
|
||||||
write to other players than `player` the packet `packetName` with fields `packetFields`
|
|
||||||
|
|
||||||
#### player._writeOthersNearby(packetName, packetFields)
|
|
||||||
|
|
||||||
write to other players in same world that are within 150 blocks (see player.getNearby())
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-runtime": "^5.4.4",
|
"babel-runtime": "^5.4.4",
|
||||||
|
"emit-then": "^1.0.2",
|
||||||
"minecraft-data": "0.7.0",
|
"minecraft-data": "0.7.0",
|
||||||
"minecraft-protocol": "0.16.2",
|
"minecraft-protocol": "0.16.2",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
|
|
@ -32,10 +33,10 @@
|
||||||
"prismarine-block": "0.1.0",
|
"prismarine-block": "0.1.0",
|
||||||
"prismarine-chunk": "0.2.1",
|
"prismarine-chunk": "0.2.1",
|
||||||
"prismarine-entity": "0.1.0",
|
"prismarine-entity": "0.1.0",
|
||||||
"prismarine-world": "0.3.3",
|
|
||||||
"prismarine-world-sync": "0.1.0",
|
|
||||||
"prismarine-item": "0.0.0",
|
"prismarine-item": "0.0.0",
|
||||||
"prismarine-windows": "0.0.0",
|
"prismarine-windows": "0.0.0",
|
||||||
|
"prismarine-world": "0.3.3",
|
||||||
|
"prismarine-world-sync": "0.1.0",
|
||||||
"random-seed": "^0.2.0",
|
"random-seed": "^0.2.0",
|
||||||
"request-promise": "^0.4.3",
|
"request-promise": "^0.4.3",
|
||||||
"requireindex": "~1.0.0",
|
"requireindex": "~1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ var EventEmitter = require('events').EventEmitter;
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var requireIndex = require('requireindex');
|
var requireIndex = require('requireindex');
|
||||||
var plugins = requireIndex(path.join(__dirname, 'lib', 'plugins'));
|
var plugins = requireIndex(path.join(__dirname, 'lib', 'plugins'));
|
||||||
|
require('emit-then').register();
|
||||||
if (process.env.NODE_ENV === 'dev'){
|
if (process.env.NODE_ENV === 'dev'){
|
||||||
require('longjohn');
|
require('longjohn');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,25 @@
|
||||||
module.exports = (obj) => {
|
module.exports = (obj) => {
|
||||||
return async (eventName, data, func, opt) => {
|
return async (eventName, data, func, cancelFunc) => {
|
||||||
var hiddenCancelled = false;
|
var hiddenCancelled = false;
|
||||||
var cancelled = false;
|
var cancelled = false;
|
||||||
var cancelCount = 0;
|
var cancelCount = 0;
|
||||||
var cancel = (hidden) => { // Hidden shouldn't be used often but it's not hard to implement so meh
|
var defaultCancel = true;
|
||||||
|
var cancel = (dC=true, hidden=false) => { // Hidden shouldn't be used often but it's not hard to implement so meh
|
||||||
if (hidden) hiddenCancelled = true;
|
if (hidden) hiddenCancelled = true;
|
||||||
else {
|
else {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
cancelCount++;
|
cancelCount++;
|
||||||
}
|
}
|
||||||
|
defaultCancel = dC;
|
||||||
}
|
}
|
||||||
|
|
||||||
await obj.emit(eventName + '_cancel', data, cancel);
|
await obj.emitThen(eventName + '_cancel', data, cancel).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
await obj.emit(eventName, data, cancelled, cancelCount);
|
await obj.emitThen(eventName, data, cancelled, cancelCount).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
|
|
||||||
if (!hiddenCancelled && !cancelled) await func(data);
|
if (!hiddenCancelled && !cancelled) await func(data).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
|
else if (cancelFunc && defaultCancel) await cancelFunc(data).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
|
|
||||||
await obj.emit(eventName + '_done', data, cancelled);
|
await obj.emitThen(eventName + '_done', data, cancelled).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
module.exports.player=function(player)
|
module.exports.player=function(player)
|
||||||
{
|
{
|
||||||
player._client.on("arm_animation", () =>
|
player._client.on("arm_animation", () =>
|
||||||
player._writeOthersNearby("animation", {
|
player.behavior('punch', {}, () => {
|
||||||
entityId: player.id,
|
player._writeOthersNearby("animation", {
|
||||||
animation: 0
|
entityId: player.id,
|
||||||
}));
|
animation: 0
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
player._client.on("entity_action", ({actionId} = {}) => {
|
player._client.on("entity_action", ({actionId} = {}) => {
|
||||||
if(actionId == 3) {
|
if(actionId == 3) {
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,17 @@ module.exports.player=function(player,serv)
|
||||||
};
|
};
|
||||||
|
|
||||||
player.sendBlock = (position, blockType, blockData) => // Call from player.setBlock unless you want "local" fake blocks
|
player.sendBlock = (position, blockType, blockData) => // Call from player.setBlock unless you want "local" fake blocks
|
||||||
player._client.write("block_change",{
|
player.behavior('sendBlock', {
|
||||||
|
position: position,
|
||||||
|
id: blockType,
|
||||||
|
data: blockData
|
||||||
|
}, ({position, id, damage}) => {
|
||||||
|
player._client.write("block_change",{
|
||||||
location:position,
|
location:position,
|
||||||
type:blockType<<4 | blockData
|
type:blockType<<4 | blockData
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
player.setBlock = (position,blockType,blockData) => serv.setBlock(player.world,position,blockType,blockData);
|
player.setBlock = (position,blockType,blockData) => serv.setBlock(player.world,position,blockType,blockData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,19 @@ module.exports.player=function(player,serv)
|
||||||
{
|
{
|
||||||
player._client.on('chat', ({message} = {}) => {
|
player._client.on('chat', ({message} = {}) => {
|
||||||
if(message[0]=="/") {
|
if(message[0]=="/") {
|
||||||
var command = message.slice(1);
|
player.behavior('command', {
|
||||||
player.handleCommand(command);
|
command: message.slice(1)
|
||||||
|
}, ({command}) => {
|
||||||
|
player.handleCommand(command);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
serv.broadcast('<' + player.username + '>' + ' ' + message);
|
player.behavior('chat', {
|
||||||
player.emit("chat",message);
|
message: message,
|
||||||
|
broadcastMessage: '<' + player.username + '>' + ' ' + message
|
||||||
|
}, ({message, broadcast, broadcastMessage}) => {
|
||||||
|
serv.broadcast(broadcastMessage);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,6 @@ module.exports.player=function(player) {
|
||||||
|
|
||||||
|
|
||||||
player.handleCommand = (str) => {
|
player.handleCommand = (str) => {
|
||||||
player.commands.use(str);
|
player.commands.use(str).catch((err)=> setTimeout(() => {throw err;},0));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,12 @@ module.exports.server=function(serv) {
|
||||||
serv.on('tick', (delta,count) => {
|
serv.on('tick', (delta,count) => {
|
||||||
if (!serv.doDaylightCycle) return;
|
if (!serv.doDaylightCycle) return;
|
||||||
if (count % 20 == 0) {
|
if (count % 20 == 0) {
|
||||||
serv.setTime((serv.time + 20) % 24000); // Vanilla only does it every second
|
serv.behavior('changeTime', {
|
||||||
|
old: serv.time,
|
||||||
|
newTime: serv.time + 20
|
||||||
|
}, ({newTime}) => {
|
||||||
|
serv.setTime((serv.time + 20) % 24000); // Vanilla only does it every second
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,48 +2,36 @@ var Vec3 = require("vec3").Vec3;
|
||||||
|
|
||||||
module.exports.player=function(player,serv)
|
module.exports.player=function(player,serv)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
function cancelDig({position, block}) {
|
||||||
|
player.sendBlock(position, block.type, block.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
player._client.on("block_dig",({location,status} = {}) => {
|
player._client.on("block_dig",({location,status} = {}) => {
|
||||||
var pos=new Vec3(location.x,location.y,location.z);
|
var pos=new Vec3(location.x,location.y,location.z);
|
||||||
player.world.getBlock(pos)
|
player.world.getBlock(pos)
|
||||||
.then(block => {
|
.then(block => {
|
||||||
player.behavior('digPacket', {
|
currentlyDugBlock=block;
|
||||||
position: pos,
|
if(currentlyDugBlock.type==0) return;
|
||||||
status: status,
|
if(status==0 && player.gameMode!=1)
|
||||||
block: block
|
player.behavior('dig', { // Start dig survival
|
||||||
}, ({position,status,block}) => {
|
position: pos,
|
||||||
currentlyDugBlock=block;
|
block: block
|
||||||
if(currentlyDugBlock.type==0) return;
|
}, ({position}) => {
|
||||||
if(status==0 && player.gameMode!=1)
|
return startDigging(position);
|
||||||
player.behavior('dig', { // Start dig survival
|
}, cancelDig);
|
||||||
position: position,
|
else if(status==2)
|
||||||
block: block
|
completeDigging(pos);
|
||||||
}, ({position}) => {
|
else if(status==1)
|
||||||
return startDigging(position);
|
player.behavior('cancelDig', { // Cancel dig survival
|
||||||
});
|
position: pos,
|
||||||
else if(status==2)
|
block: block
|
||||||
player.behavior('finishDig', { // Finish dig survival
|
}, ({position}) => {
|
||||||
position: position,
|
return cancelDigging(position);
|
||||||
block: block
|
});
|
||||||
}, ({position}) => {
|
else if(status==0 && player.gameMode==1)
|
||||||
return completeDigging(position);
|
return creativeDigging(pos);
|
||||||
});
|
})
|
||||||
else if(status==1)
|
|
||||||
player.behavior('cancelDig', { // Cancel dig survival
|
|
||||||
position: position,
|
|
||||||
block: block
|
|
||||||
}, ({position}) => {
|
|
||||||
return cancelDigging(position);
|
|
||||||
});
|
|
||||||
else if(status==0 && player.gameMode==1)
|
|
||||||
player.behavior('dig', { // Start/finish dig creative
|
|
||||||
position: position,
|
|
||||||
block: block
|
|
||||||
}, ({position}) => {
|
|
||||||
return creativeDigging(position);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
)
|
|
||||||
.catch((err)=> setTimeout(() => {throw err;},0))
|
.catch((err)=> setTimeout(() => {throw err;},0))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -75,12 +63,20 @@ module.exports.player=function(player,serv)
|
||||||
newDestroyState=newDestroyState>9 ? 9 : newDestroyState;
|
newDestroyState=newDestroyState>9 ? 9 : newDestroyState;
|
||||||
if(newDestroyState!=lastDestroyState)
|
if(newDestroyState!=lastDestroyState)
|
||||||
{
|
{
|
||||||
lastDestroyState=newDestroyState;
|
player.behavior('breakAnimation', {
|
||||||
player._writeOthersNearby("block_break_animation",{
|
lastState: lastDestroyState,
|
||||||
"entityId":currentAnimationId,
|
state: newDestroyState,
|
||||||
"location":location,
|
start: startDigging,
|
||||||
"destroyStage":newDestroyState
|
timePassed: currentDiggingTime,
|
||||||
});
|
position: location
|
||||||
|
}, ({lastState, state}) => {
|
||||||
|
lastDestroyState=state;
|
||||||
|
player._writeOthersNearby("block_break_animation",{
|
||||||
|
"entityId":currentAnimationId,
|
||||||
|
"location":location,
|
||||||
|
"destroyStage":state
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -99,14 +95,32 @@ module.exports.player=function(player,serv)
|
||||||
{
|
{
|
||||||
clearInterval(animationInterval);
|
clearInterval(animationInterval);
|
||||||
var diggingTime=new Date()-startDiggingTime;
|
var diggingTime=new Date()-startDiggingTime;
|
||||||
|
var stop = false;
|
||||||
if(expectedDiggingTime-diggingTime<100) {
|
if(expectedDiggingTime-diggingTime<100) {
|
||||||
player.changeBlock(location,0,0);
|
stop = true;
|
||||||
// Drop block
|
stop = player.behavior('forceCancelDig', {
|
||||||
serv.spawnObject(2, player.world, location.offset(0.5, 0.5, 0.5), {
|
stop: true,
|
||||||
velocity: new Vec3(Math.random()*4 - 2, Math.random()*2 + 2, Math.random()*4 - 2),
|
start: startDiggingTime,
|
||||||
itemId: currentlyDugBlock.type,
|
time: diggingTime
|
||||||
itemDamage: currentlyDugBlock.metadata
|
}).stop;
|
||||||
});
|
}
|
||||||
|
if(!stop) {
|
||||||
|
player.behavior('dug', {
|
||||||
|
position: location,
|
||||||
|
block: currentlyDugBlock,
|
||||||
|
dropBlock: true,
|
||||||
|
blockDropPosition: location.offset(0.5, 0.5, 0.5),
|
||||||
|
blockDropWorld: player.world,
|
||||||
|
blockDropVelocity: new Vec3(Math.random()*4 - 2, Math.random()*2 + 2, Math.random()*4 - 2),
|
||||||
|
blockDropId: currentlyDugBlock.type,
|
||||||
|
blockDropDamage: currentlyDugBlock.metadata,
|
||||||
|
blockDropPickup: 500,
|
||||||
|
blockDropDeath: 60*5*1000
|
||||||
|
}, (data) => {
|
||||||
|
player.changeBlock(data.position,0,0);
|
||||||
|
console.log('dropping',data.dropBlock);
|
||||||
|
if (data.dropBlock) dropBlock(data);
|
||||||
|
}, cancelDig)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -117,10 +131,34 @@ module.exports.player=function(player,serv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dropBlock({blockDropPosition, blockDropWorld, blockDropVelocity, blockDropId, blockDropDamage, blockDropPickup, blockDropDeath}) {
|
||||||
|
serv.spawnObject(2, blockDropWorld, blockDropPosition, {
|
||||||
|
velocity: blockDropVelocity,
|
||||||
|
itemId: blockDropId,
|
||||||
|
itemDamage: blockDropDamage,
|
||||||
|
pickupTime: blockDropPickup,
|
||||||
|
deathTime: blockDropDeath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function creativeDigging(location)
|
function creativeDigging(location)
|
||||||
{
|
{
|
||||||
return player.changeBlock(location,0,0);
|
player.behavior('dug', {
|
||||||
|
position: location,
|
||||||
|
block: currentlyDugBlock,
|
||||||
|
dropBlock: false,
|
||||||
|
blockDropPosition: location.offset(0.5, 0.5, 0.5),
|
||||||
|
blockDropWorld: player.world,
|
||||||
|
blockDropVelocity: new Vec3(Math.random()*4 - 2, Math.random()*2 + 2, Math.random()*4 - 2),
|
||||||
|
blockDropId: currentlyDugBlock.type,
|
||||||
|
blockDropDamage: currentlyDugBlock.metadata,
|
||||||
|
blockDropPickup: 500,
|
||||||
|
blockDropDeath: 60*5*1000
|
||||||
|
}, (data) => {
|
||||||
|
player.changeBlock(data.position,0,0);
|
||||||
|
if (data.dropBlock) dropBlock(data);
|
||||||
|
}, cancelDig);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -25,7 +25,7 @@ module.exports.server=function(serv,options) {
|
||||||
return entity;
|
return entity;
|
||||||
};
|
};
|
||||||
|
|
||||||
serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0}={}) => {
|
serv.spawnObject = (type, world, position, {pitch=0,yaw=0,velocity=new Vec3(0,0,0),data=1,itemId,itemDamage=0,pickupTime=500,deathTime=60*1000}={}) => {
|
||||||
var object = serv.initEntity('object', type, world, position.scaled(32).floored());
|
var object = serv.initEntity('object', type, world, position.scaled(32).floored());
|
||||||
object.data = data;
|
object.data = data;
|
||||||
object.velocity = velocity.scaled(32).floored();
|
object.velocity = velocity.scaled(32).floored();
|
||||||
|
|
@ -35,8 +35,8 @@ module.exports.server=function(serv,options) {
|
||||||
object.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
|
object.terminalvelocity = new Vec3(27*32, 27*32, 27*32);
|
||||||
object.friction = new Vec3(15*32, 0, 15*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.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.deathTime = deathTime;
|
||||||
object.pickupTime = 200;
|
object.pickupTime = pickupTime;
|
||||||
object.itemId = itemId;
|
object.itemId = itemId;
|
||||||
object.itemDamage = itemDamage;
|
object.itemDamage = itemDamage;
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ module.exports.entity=function(entity,serv){
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
entity.on("positionChanged",() => {
|
entity.on("move",() => {
|
||||||
if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32)
|
if(entity.position.distanceTo(entity.lastPositionPlayersUpdated)>2*32)
|
||||||
entity.updateAndSpawn();
|
entity.updateAndSpawn();
|
||||||
});
|
});
|
||||||
|
|
@ -259,7 +259,8 @@ module.exports.entity=function(entity,serv){
|
||||||
|
|
||||||
entity.collect = (collectEntity) => {
|
entity.collect = (collectEntity) => {
|
||||||
if (entity.type != 'player'){
|
if (entity.type != 'player'){
|
||||||
serv.emit('error', 'Non-player entity (ttype ' + entity.type + ') cannot collect another entity')
|
console.log('[ERROR] Non-player entity (type ' + entity.type + ') cannot collect another entity');
|
||||||
|
console.log((new Error()).stack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
module.exports.server = function(serv, settings) {
|
module.exports.server = function(serv, settings) {
|
||||||
serv.plugins = {};
|
serv.plugins = {};
|
||||||
serv.pluginCount = 0;
|
serv.pluginCount = 0;
|
||||||
|
|
@ -19,15 +21,19 @@ module.exports.server = function(serv, settings) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var p in settings.plugins) {
|
for (var p in settings.plugins) {
|
||||||
|
if (settings.plugins[p].disabled) continue;
|
||||||
try {
|
try {
|
||||||
serv.addPlugin(p, require(p), settings.plugins[p]);
|
require.resolve(p); // Check if it exists, if not do catch, otherwise jump to bottom
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
try {
|
try { // Throw error if cannot find plugin
|
||||||
serv.addPlugin(p, require('../../plugins/' + p), settings.plugins[p]);
|
fs.accessSync('./dist/plugins/' + p);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error('Cannot find plugin "' + p + '"');
|
throw new Error('Cannot find plugin "' + p + '"');
|
||||||
}
|
}
|
||||||
|
serv.addPlugin(p, require('../../plugins/' + p), settings.plugins[p]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
serv.addPlugin(p, require(p), settings.plugins[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var p in serv.plugins) {
|
for (var p in serv.plugins) {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ module.exports.player=function(player,serv)
|
||||||
|
|
||||||
player.on("disconnected",() => serv.log("[INFO]: " + player.username + ' disconnected'));
|
player.on("disconnected",() => serv.log("[INFO]: " + player.username + ' disconnected'));
|
||||||
|
|
||||||
player.on("chat", message => serv.log("[INFO] " + '<' + player.username + '>' + ' ' + message));
|
player.on("chat", ({message}) => serv.log("[INFO] " + '<' + player.username + '>' + ' ' + message));
|
||||||
|
|
||||||
player.on("kicked",(kicker,reason) =>
|
player.on("kicked",(kicker,reason) =>
|
||||||
serv.log(kicker.username + " kicked " + player.username + (reason ? " (" + reason + ")" : "")));
|
serv.log(kicker.username + " kicked " + player.username + (reason ? " (" + reason + ")" : "")));
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@ module.exports.player=function(player,serv)
|
||||||
position: placedPosition,
|
position: placedPosition,
|
||||||
reference: referencePosition,
|
reference: referencePosition,
|
||||||
playSound: true,
|
playSound: true,
|
||||||
sound: 'dig.' + (materialToSound[blocks[heldItem.blockId].material] || 'stone')
|
sound: 'dig.' + (materialToSound[blocks[heldItem.blockId].material] || 'stone'),
|
||||||
}, ({direction, heldItem, position, reference, playSound, sound}) => {
|
}, ({direction, heldItem, position, reference, playSound, sound, id, damage}) => {
|
||||||
if (playSound) {
|
if (playSound) {
|
||||||
serv.playSound(sound, player.world, placedPosition.clone().add(new Vec3(0.5, 0.5, 0.5)), {
|
serv.playSound(sound, player.world, placedPosition.clone().add(new Vec3(0.5, 0.5, 0.5)), {
|
||||||
pitch: 0.8
|
pitch: 0.8
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(heldItem.blockId!=323){
|
if(heldItem.blockId!=323){
|
||||||
player.changeBlock(position,heldItem.blockId,heldItem.itemDamage);
|
player.changeBlock(position, id, damage);
|
||||||
}else if(direction==1){
|
}else if(direction==1){
|
||||||
player.setBlock(position, 63, 0);
|
player.setBlock(position, 63, 0);
|
||||||
player._client.write('open_sign_entity', {
|
player._client.write('open_sign_entity', {
|
||||||
|
|
@ -46,6 +46,10 @@ module.exports.player=function(player,serv)
|
||||||
location:position
|
location:position
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}, async () => {
|
||||||
|
var id = await player.world.getBlockType(placedPosition);
|
||||||
|
var damage = await player.world.getBlockData(placedPosition);
|
||||||
|
player.sendBlock(placedPosition, id, damage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,31 @@ module.exports.player=function(player,serv)
|
||||||
var attackedEntity = serv.entities[entityId];
|
var attackedEntity = serv.entities[entityId];
|
||||||
if(!attackedEntity || (attackedEntity.gameMode != 0 && attackedEntity.type == 'player')) return;
|
if(!attackedEntity || (attackedEntity.gameMode != 0 && attackedEntity.type == 'player')) return;
|
||||||
|
|
||||||
attackedEntity.updateHealth(attackedEntity.health - 1);
|
player.behavior('attack', {
|
||||||
serv.playSound('game.player.hurt', player.world, attackedEntity.position.scaled(1/32));
|
attackedEntity: attackedEntity,
|
||||||
|
sound: 'game.player.hurt',
|
||||||
|
playSound: true,
|
||||||
|
damage: 1,
|
||||||
|
velocity: attackedEntity.position.minus(player.position).plus(new Vec3(0, 0.5, 0)).scaled(5),
|
||||||
|
maxVelocity: new Vec3(4, 4, 4),
|
||||||
|
animation: true
|
||||||
|
}, ({attackedEntity, sound, playSound, damage, velocity, maxVelocity, animation}) => {
|
||||||
|
attackedEntity.updateHealth(attackedEntity.health - damage);
|
||||||
|
serv.playSound(sound, player.world, attackedEntity.position.scaled(1/32));
|
||||||
|
|
||||||
var attackVelocity = attackedEntity.position.minus(player.position).plus(new Vec3(0, 0.5, 0)).scaled(5/32);
|
attackedEntity.sendVelocity(velocity.scaled(1/32), maxVelocity);
|
||||||
attackedEntity.sendVelocity(attackVelocity, new Vec3(4, 4, 4));
|
|
||||||
|
|
||||||
if(attackedEntity.health<=0)
|
if(attackedEntity.health<=0 && animation)
|
||||||
attackedEntity._writeOthers('entity_status',{
|
attackedEntity._writeOthers('entity_status',{
|
||||||
|
entityId:attackedEntity.id,
|
||||||
|
entityStatus:3
|
||||||
|
});
|
||||||
|
else if (animation)
|
||||||
|
attackedEntity._writeOthers('animation',{
|
||||||
entityId:attackedEntity.id,
|
entityId:attackedEntity.id,
|
||||||
entityStatus:3
|
animation:1
|
||||||
});
|
});
|
||||||
else
|
});
|
||||||
attackedEntity._writeOthers('animation',{
|
|
||||||
entityId:attackedEntity.id,
|
|
||||||
animation:1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player._client.on("use_entity", ({mouse,target} = {}) => {
|
player._client.on("use_entity", ({mouse,target} = {}) => {
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,18 @@ module.exports.player=function(player)
|
||||||
{
|
{
|
||||||
player._client.on("client_command", ({payload}) => {
|
player._client.on("client_command", ({payload}) => {
|
||||||
if(payload == 0) {
|
if(payload == 0) {
|
||||||
player._client.write("respawn",{
|
player.behavior('requestRespawn', {}, () => {
|
||||||
dimension:0,
|
player._client.write("respawn",{
|
||||||
difficulty:0,
|
dimension:0,
|
||||||
gamemode:player.gameMode,
|
difficulty:0,
|
||||||
levelType:'default'
|
gamemode:player.gameMode,
|
||||||
|
levelType:'default'
|
||||||
|
});
|
||||||
|
player.sendPosition();
|
||||||
|
player.updateHealth(20);
|
||||||
|
player.nearbyEntities=[];
|
||||||
|
player.updateAndSpawn();
|
||||||
});
|
});
|
||||||
player.sendPosition();
|
|
||||||
player.updateHealth(20);
|
|
||||||
player.nearbyEntities=[];
|
|
||||||
player.updateAndSpawn();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -40,30 +40,27 @@ module.exports.player=function(player,serv) {
|
||||||
serv.playSound(sound, player.world, null, opt);
|
serv.playSound(sound, player.world, null, opt);
|
||||||
};
|
};
|
||||||
|
|
||||||
player._client.on('block_place', ({location}={}) => {
|
player.on('placeBlock_cancel', async ({position, reference}, cancel) => {
|
||||||
if (player.crouching) return;
|
if (player.crouching) return;
|
||||||
var pos=new Vec3(location.x,location.y,location.z);
|
var id = await player.world.getBlockType(reference);
|
||||||
player.world.getBlockType(pos).then((id) => {
|
if (id != 25) return;
|
||||||
if (id != 25) return;
|
cancel(false);
|
||||||
if (!player.world.blockEntityData[pos.toString()]) player.world.blockEntityData[pos.toString()] = {};
|
if (!player.world.blockEntityData[reference.toString()]) player.world.blockEntityData[reference.toString()] = {};
|
||||||
var data = player.world.blockEntityData[pos.toString()];
|
var data = player.world.blockEntityData[reference.toString()];
|
||||||
if (typeof data.note == 'undefined') data.note = -1;
|
if (typeof data.note == 'undefined') data.note = -1;
|
||||||
data.note++;
|
data.note++;
|
||||||
data.note %= 25;
|
data.note %= 25;
|
||||||
serv.playNoteBlock(data.note, player.world, pos);
|
serv.playNoteBlock(data.note, player.world, reference);
|
||||||
}).catch((err)=> setTimeout(() => {throw err;},0));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
player._client.on('block_dig', ({location,status} = {}) => {
|
player.on('dig_cancel', async ({position}, cancel) => {
|
||||||
if (status != 0 || player.gameMode == 1) return;
|
var id = await player.world.getBlockType(position);
|
||||||
var pos=new Vec3(location.x,location.y,location.z);
|
if (id != 25) return;
|
||||||
player.world.getBlockType(pos).then((id) => {
|
cancel(false);
|
||||||
if (id != 25) return;
|
if (!player.world.blockEntityData[position.toString()]) player.world.blockEntityData[position.toString()] = {};
|
||||||
if (!player.world.blockEntityData[pos.toString()]) player.world.blockEntityData[pos.toString()] = {};
|
var data = player.world.blockEntityData[position.toString()];
|
||||||
var data = player.world.blockEntityData[pos.toString()];
|
if (typeof data.note == 'undefined') data.note = 0;
|
||||||
if (typeof data.note == 'undefined') data.note = 0;
|
serv.playNoteBlock(data.note ,player.world, position);
|
||||||
serv.playNoteBlock(data.not,player.world, pos, data.note);
|
|
||||||
}).catch((err)=> setTimeout(() => {throw err;},0));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,29 @@ module.exports.player=function(player)
|
||||||
}
|
}
|
||||||
function sendLook(yaw,pitch,onGround)
|
function sendLook(yaw,pitch,onGround)
|
||||||
{
|
{
|
||||||
var convYaw=conv(yaw);
|
player.behavior('look', {
|
||||||
var convPitch=conv(pitch);
|
yaw: yaw,
|
||||||
if (convYaw == player.yaw && convPitch == player.pitch) return;
|
pitch: pitch,
|
||||||
player._writeOthersNearby("entity_look", {
|
|
||||||
entityId: player.id,
|
|
||||||
yaw: convYaw,
|
|
||||||
pitch: convPitch,
|
|
||||||
onGround: onGround
|
onGround: onGround
|
||||||
});
|
}, () => {
|
||||||
player.yaw = convYaw;
|
var convYaw=conv(yaw);
|
||||||
player.pitch = convPitch;
|
var convPitch=conv(pitch);
|
||||||
player.onGround = onGround;
|
if (convYaw == player.yaw && convPitch == player.pitch) return;
|
||||||
player._writeOthersNearby("entity_head_rotation", {
|
player._writeOthersNearby("entity_look", {
|
||||||
entityId: player.id,
|
entityId: player.id,
|
||||||
headYaw: convYaw
|
yaw: convYaw,
|
||||||
|
pitch: convPitch,
|
||||||
|
onGround: onGround
|
||||||
|
});
|
||||||
|
player.yaw = convYaw;
|
||||||
|
player.pitch = convPitch;
|
||||||
|
player.onGround = onGround;
|
||||||
|
player._writeOthersNearby("entity_head_rotation", {
|
||||||
|
entityId: player.id,
|
||||||
|
headYaw: convYaw
|
||||||
|
});
|
||||||
|
}, () => {
|
||||||
|
player.sendPosition();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,33 +52,39 @@ module.exports.player=function(player)
|
||||||
});
|
});
|
||||||
|
|
||||||
function sendRelativePositionChange(newPosition, onGround) {
|
function sendRelativePositionChange(newPosition, onGround) {
|
||||||
if (player.position.distanceTo(new Vec3(0, 0, 0)) != 0) {
|
player.behavior('move', {
|
||||||
var diff = newPosition.minus(player.position);
|
onGround: onGround,
|
||||||
if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127)
|
position: newPosition
|
||||||
{
|
}, () => {
|
||||||
player._writeOthersNearby('entity_teleport', {
|
if (player.position.distanceTo(new Vec3(0, 0, 0)) != 0) {
|
||||||
entityId:player.id,
|
var diff = newPosition.minus(player.position);
|
||||||
x: newPosition.x,
|
if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127)
|
||||||
y: newPosition.y,
|
{
|
||||||
z: newPosition.z,
|
player._writeOthersNearby('entity_teleport', {
|
||||||
yaw: player.yaw,
|
entityId:player.id,
|
||||||
pitch: player.pitch,
|
x: newPosition.x,
|
||||||
onGround: onGround
|
y: newPosition.y,
|
||||||
});
|
z: newPosition.z,
|
||||||
|
yaw: player.yaw,
|
||||||
|
pitch: player.pitch,
|
||||||
|
onGround: onGround
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) {
|
||||||
|
player._writeOthersNearby('rel_entity_move', {
|
||||||
|
entityId: player.id,
|
||||||
|
dX: diff.x,
|
||||||
|
dY: diff.y,
|
||||||
|
dZ: diff.z,
|
||||||
|
onGround: onGround
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) {
|
player.position = newPosition;
|
||||||
player._writeOthersNearby('rel_entity_move', {
|
player.onGround = onGround;
|
||||||
entityId: player.id,
|
}, () => {
|
||||||
dX: diff.x,
|
player.sendPosition();
|
||||||
dY: diff.y,
|
});
|
||||||
dZ: diff.z,
|
|
||||||
onGround: onGround
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
player.position = newPosition;
|
|
||||||
player.onGround = onGround;
|
|
||||||
player.emit("positionChanged");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendPosition = () => {
|
player.sendPosition = () => {
|
||||||
|
|
@ -87,26 +101,31 @@ module.exports.player=function(player)
|
||||||
|
|
||||||
module.exports.entity=function(entity,serv){
|
module.exports.entity=function(entity,serv){
|
||||||
entity.sendPosition = ({oldPos,onGround}) => {
|
entity.sendPosition = ({oldPos,onGround}) => {
|
||||||
var diff = entity.position.minus(oldPos);
|
entity.behavior('move', {
|
||||||
|
old: oldPos,
|
||||||
if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127)
|
|
||||||
entity._writeOthersNearby('entity_teleport', {
|
|
||||||
entityId: entity.id,
|
|
||||||
x: entity.position.x,
|
|
||||||
y: entity.position.y,
|
|
||||||
z: entity.position.z,
|
|
||||||
yaw: entity.yaw,
|
|
||||||
pitch: entity.pitch,
|
|
||||||
onGround: onGround
|
|
||||||
});
|
|
||||||
else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) serv._writeNearby('rel_entity_move', {
|
|
||||||
entityId: entity.id,
|
|
||||||
dX: diff.x,
|
|
||||||
dY: diff.y,
|
|
||||||
dZ: diff.z,
|
|
||||||
onGround: onGround
|
onGround: onGround
|
||||||
}, entity);
|
}, ({old,onGround}) => {
|
||||||
|
var diff = entity.position.minus(oldPos);
|
||||||
|
|
||||||
entity.emit('positionChanged', oldPos);
|
if(diff.abs().x>127 || diff.abs().y>127 || diff.abs().z>127)
|
||||||
|
entity._writeOthersNearby('entity_teleport', {
|
||||||
|
entityId: entity.id,
|
||||||
|
x: entity.position.x,
|
||||||
|
y: entity.position.y,
|
||||||
|
z: entity.position.z,
|
||||||
|
yaw: entity.yaw,
|
||||||
|
pitch: entity.pitch,
|
||||||
|
onGround: onGround
|
||||||
|
});
|
||||||
|
else if (diff.distanceTo(new Vec3(0, 0, 0)) != 0) serv._writeNearby('rel_entity_move', {
|
||||||
|
entityId: entity.id,
|
||||||
|
dX: diff.x,
|
||||||
|
dY: diff.y,
|
||||||
|
dZ: diff.z,
|
||||||
|
onGround: onGround
|
||||||
|
}, entity);
|
||||||
|
}, () => {
|
||||||
|
entity.position = oldPos;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -70,14 +70,20 @@ module.exports.player=function(player,serv) {
|
||||||
|
|
||||||
player.sendChunk = (chunkX,chunkZ,column) =>
|
player.sendChunk = (chunkX,chunkZ,column) =>
|
||||||
{
|
{
|
||||||
player._client.write('map_chunk', {
|
return player.behavior('sendChunk', {
|
||||||
x: chunkX,
|
x: chunkX,
|
||||||
z: chunkZ,
|
z: chunkZ,
|
||||||
groundUp: true,
|
chunk: column
|
||||||
bitMap: 0xffff,
|
}, ({x, z, chunk}) => {
|
||||||
chunkData: column.dump()
|
player._client.write('map_chunk', {
|
||||||
});
|
x: x,
|
||||||
return Promise.resolve();
|
z: z,
|
||||||
|
groundUp: true,
|
||||||
|
bitMap: 0xffff,
|
||||||
|
chunkData: chunk.dump()
|
||||||
|
});
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
function spiral(arr)
|
function spiral(arr)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue