93 Commits

Author SHA1 Message Date
Dylan K. Taylor
dec235abab World: don't create a new chunk just to read biome info
the chunk won't be generated, so we can provide the default result without creating a new chunk for no reason.
2020-10-31 21:29:39 +00:00
Dylan K. Taylor
de867f1b86 World: don't create an empty chunk just for accessing the highest block
this is pointless since the chunk will not be generated anyway, so it serves no end to create it.
2020-10-31 21:27:16 +00:00
Dylan K. Taylor
f0d62cf4ce World: don't try to load chunks to read light levels
sync chunk load is useless here because lighting isn't immediately calculated anyway and it isn't available directly from the chunk when loaded.
2020-10-31 20:38:15 +00:00
Dylan K. Taylor
5f7b0994b9 World: rename get(HighestAdjacent)BlockSkyLight(At) to make it clear these are **potentials**, not the actual light level 2020-10-31 16:47:34 +00:00
Dylan K. Taylor
241a50387b World: added getHighestAdjacentRealBlockSkyLight()
this is the same as its 'non-real' counterpart, but it accounts for time of day.
2020-10-31 16:44:42 +00:00
Dylan K. Taylor
66edf5a165 Particle::encode() now always returns ClientboundPacket[] 2020-10-31 15:51:17 +00:00
Dylan K. Taylor
5a320f22b7 Sound::encode() now always returns an array 2020-10-31 15:48:46 +00:00
Dylan K. Taylor
058bb3a91a World: do not execute neighbour block updates on unloaded chunks
we might also need to delay this if any adjacent chunk is also not loaded, in case the block wants to access adjacent blocks during its neighbour update.
2020-10-29 13:37:14 +00:00
Dylan K. Taylor
cfb9cc8999 fix build failure 2020-10-29 13:22:35 +00:00
Dylan K. Taylor
b079772d32 World: do not include unloaded or unlit chunks in getHighestAdjacentBlock(Sky)Light() 2020-10-29 13:05:25 +00:00
Dylan K. Taylor
3c892182fd World: change some usages of getOrLoadChunk() to getChunk()
these usages don't require getOrLoadChunk() because they already check for unloaded chunks anyway.
2020-10-29 12:57:33 +00:00
Dylan K. Taylor
3e1263eb79 Chunk: remove all proxy APIs to lighting information
these aren't used by internals and they shouldn't be used by plugins either.
2020-10-29 12:11:06 +00:00
Dylan K. Taylor
286ac2a975 Rework World::blockHash() to use morton3d
this uses the unused bits on the Y component to expand the X/Z axes to 2^27 blocks long instead of 2^21 permitted by a regular morton3d code. It does require the sacrifice of an additional bit on the Y axis, but the performance advantages are more than worth it.
I'm exploring how realistic it would be to just eliminate blockHash global usage (currently in lighting updates and explosions). This would allow scaling up to 2^32 without larger hashes (morton2d for chunks).
2020-10-20 20:31:10 +01:00
Dylan K. Taylor
0f9d5f7011 ext-morton is now required and used for World::chunkHash() and World::chunkBlockHash() 2020-10-17 16:09:30 +01:00
Dylan K. Taylor
eabfd2a37b World: replace sendBlocks() with createBlockUpdatePackets()
this allows the caller to decide how the packets should be sent.
2020-10-11 16:30:54 +01:00
Dylan K. Taylor
ca9f3020b4 World: added private broadcastPacketToPlayersUsingChunk()
this is equivalent to the old addChunkPacket, but private and with a less stupid name.
2020-10-11 15:21:15 +01:00
Dylan K. Taylor
a05b1fec7e World: rename chunkPackets -> packetBuffersByChunk 2020-10-11 15:18:57 +01:00
Dylan K. Taylor
bd3bf3d0ce Revert "World: do not group broadcasted packets by chunk, broadcast directly instead"
This reverts commit b172c93e45e60ee3dbfd8a2efbede60b894673a3.

I made a significant mistake with this change: the scaling factor of
batch-by-chunk is O(nSendBytes), while the scaling factor of sending
directly to players is O(nSendBytes * nActivePlayers). It seems like the
real problem is that this system isn't getting enough usage.

While it does reduce compression efficiency in some cases, it falls back
to letting the sessions do individual compression when the amount of
data is less than 256 bytes anyway (compression-threshold in
pocketmine.yml).

My motivation for scrapping this system was to reduce the broadcast
system's complexity to make it easier to thread the living shit out of
compression, but it seems like this change was a step in the wrong
direction for performance.

A few steps can be taken to improve the usefulness of this system (and
also improve output bandwidth):
- Make general entity updates use this system. Movement and velocity
  already kinda used this system, but crucially, players did not,
  because we couldn't prevent the player from receiving its own movement
  updates if we did that, which caused all kinds of problems.
  - Therefore, we need to reintroduce static "self" entity IDs, like we
    had in the shoghi days when entity ID 0 referred to the "self"
    player.
  - However, since entity ID 0 has a variety of interesting bugs since
    it usually refers to "no entity" in MCPE, it would be better to use
    1 (or 2, like MiNET does).
  - The fixed ID used should be close to zero to maximize varint
    encoding efficiency.
  - We assumed that changes to player's position and velocity would be
    ignored by the client. This assumption depends on the client and
    could be broken at any time, so it's best not to rely on it.
- Make block updates use this system (when chunk updates are not sent).
  Currently, block updates use a separate mechanism which creates a
  second batch for every active chunk, which wastes CPU, and decreases
  bandwidth efficiency on multiple fronts (reduced compression
  efficiency, more cross-thread interactions, more bytes wasted on
  RakNet packet headers).
2020-10-11 14:55:54 +01:00
Dylan K. Taylor
b172c93e45 World: do not group broadcasted packets by chunk, broadcast directly instead
Grouping packets to batch by chunk instead of by player reduces bandwidth efficiency, because the number of active chunks is almost always larger than the number of active players.
With the old mechanism, a batch of packets for each active chunk (which could be dozens, or hundreds... or thousands) would be created once, and then sent to many players. This makes the compression load factor O(nActiveChunks). Broadcasting directly is simpler and changes the load factor to O(nActivePlayers), which usually means a smaller number of larger batches are created, achieving better compression ratios for approximately the same cost (the same amount of data is being compressed, just in a different way).
2020-10-06 17:27:17 +01:00
Dylan K. Taylor
d3a3a41d2b Revert back to separated floor/wall sign
the conditionally useless properties are problematic.
2020-10-04 17:52:23 +01:00
Dylan K. Taylor
7b02cc3efd Implemented #3836: Replace setCancelled() in events with cancel() and uncancel()
The motivation for this is to prevent passing a dynamic argument to cancellation, which in almost all cases is a bug in user code. This same mistake also appears in a few places in the PM core (as seen in this commit), but in those cases the mistakes were mostly harmless since they were taking place before the event was actually called.
closes #3836
2020-09-26 14:31:56 +01:00
Dylan K. Taylor
89cce4c749 performance: only calculate light for chunks inside ticking areas
this produces a major performance improvement for large render distances, and reduces the impact of lighting calculation to zero on servers which have random blockupdates turned off.
2020-09-26 13:13:12 +01:00
Dylan K. Taylor
b727972c76 World: remove useless isLightPopulated() check
chunks are never light populated when loaded from disk now.
2020-09-26 12:52:28 +01:00
Dylan K. Taylor
b252c18d34 World: Loading chunks to sync block updates is a bug
again, this should never happen, because chunk unloading cleans this stuff out. But if it did happen, loading chunks is not the way to take care of it.
2020-09-20 13:42:27 +01:00
Dylan K. Taylor
5096741b29 World::getChunk() behaviour now matches that of a regular ChunkManager
Various bugs existed for a while with stuff using chunk managers instead of worlds when interacting with terrain due to a behavioural inconsistency between World::getChunk() (return from cache or load from disk), and SimpleChunkManager::getChunk() (return from cache only). This change brings the two in line.
World::getOrLoadChunk() has been added as a replacement, which has the same behaviour as the old getChunk() and also makes it more obvious that there is an issue with code using it during refactoring.
2020-09-20 13:29:09 +01:00
Dylan K. Taylor
c9d2edcb4d Rename SubChunkIteratorManager -> SubChunkExplorer 2020-09-20 12:47:44 +01:00
Dylan K. Taylor
4879df626d Reduced LightUpdate dependency on ChunkManager to indirect
this opens the gateway for alternative SubChunkIteratorManager implementations which don't use ChunkManager at all.
2020-09-20 12:41:53 +01:00
Dylan K. Taylor
5661d0496f RuntimeBlockMapping::toRuntimeId() now accepts a single integer instead of id/meta
the expectation is that eventually this will receive arbitrary internal runtime IDs instead of static id/meta, and RuntimeBlockMapping doesn't really care about this crap anyway.
2020-09-20 12:16:11 +01:00
Dylan K. Taylor
c7070788f9 Rename and repurpose Block->diffusesSkyLight to blocksDirectSkyLight
this new form allows skipping some useless checks during sky light calculation and also allows getting rid of the last hard dependency on core Block classes.
We're getting real close to native light now.
2020-09-08 22:40:05 +01:00
Dylan K. Taylor
205617f29e Untether LightUpdate and children from BlockFactory 2020-09-08 18:14:35 +01:00
Dylan K. Taylor
2e45398072 World: skip random block ticking on chunks that don't have any light
typically this is a state that only lasts for a tick or so, but it's a race condition that is regardless very commonly encountered.
If you were very unlucky, you might have noticed grass randomly dying when you were spawning or flying around, even though it was in full sky light.
2020-09-04 18:08:42 +01:00
Dylan K. Taylor
180c0e4999 World: rely on Player being a ChunkListener instead of ChunkLoader
ChunkListeners are less dangerous, and also make more sense considering the usages.
Ideally we want to not have to care if a listener is a Player at all, but that's still some work away yet.
2020-07-11 18:20:32 +01:00
Dylan K. Taylor
f2cf453cd0 World: remove one more unnecessary vector3 field mutation 2020-07-09 12:53:16 +01:00
Dylan K. Taylor
909f3f39de Block: get rid of getRuntimeId()
the runtime ID mapping should be non-global in case of multiple protocols.
2020-07-06 11:18:29 +01:00
Dylan K. Taylor
670ad9eb9d Position: rename getWorldNonNull() to getWorld(), remove original getWorld() 2020-06-29 21:19:46 +01:00
Dylan K. Taylor
fc22fd80d8 Eradicate remaining usages of Position->getWorld() 2020-06-29 21:03:55 +01:00
Dylan K. Taylor
bf5c06f285 World: get rid of temporalPosition too (entirely unused) 2020-06-20 21:45:35 +01:00
Dylan K. Taylor
fc7672c6ba World: remove temporalVector (premature cold path optimisation again) 2020-06-20 21:44:05 +01:00
Dylan K. Taylor
4b528aa637 NBT is no longer needed to create an entity
it's still able to be provided, but shouldn't be needed in the majority of cases (constructor args and/or API methods should be sufficient).
2020-06-19 10:51:27 +01:00
Dylan K. Taylor
1205432c34 Extract mandatory parameters into constructor parameters
the goal is obviously to ditch NBT entirely here, but there's more work to be done before that becomes possible.
2020-06-19 10:51:27 +01:00
Dylan K. Taylor
6a26c0bebf EntityFactory now exclusively handles loading data from disk
this commit removes the ability to replace centrally registered entity classes in favour of using constructors directly.
In future commits I may introduce a dedicated factory interface which allows an _actual_ factory pattern (e.g. factory->createArrow(world, pos, shooter, isCritical) with proper static analysability) but for now it's peripheral to my intended objective.
The purpose of this change is to facilitate untangling of NBT from entity constructors so that they can be properly created without using NBT at all, and instead use nice APIs.

Spawn eggs now support arbitrary entity creation functions like EntityFactory does, allowing much more flexibility in what can be passed to an entity's constructor (e.g. a Plugin reference can be injected by use()ing it in a closure or via traditional DI.
2020-06-19 10:51:27 +01:00
Dylan K. Taylor
f55a7f8b53 Merge commit 'd8d994351'
# Conflicts:
#	composer.lock
#	resources/vanilla
#	tests/phpstan/configs/l7-baseline.neon
2020-06-14 19:47:21 +01:00
Dylan K. Taylor
899da1b7f7 Merge commit '42e14f749'
# Conflicts:
#	resources/vanilla
#	src/pocketmine/Player.php
#	src/pocketmine/item/Bow.php
#	src/world/World.php
2020-06-03 12:31:17 +01:00
Dylan K. Taylor
bbf3f4c476 Merge branch 'next-minor' 2020-05-31 18:40:19 +01:00
Dylan K. Taylor
fe649d8d70 Extract ServerConfigGroup from Server
this API isn't very nice, but it's pretty much the same as the original, and at least this can be _kinda_ unit-tested...
2020-05-24 15:48:03 +01:00
Dylan K. Taylor
c9af5ce7a9 Convert GeneratorManager to singleton 2020-05-23 10:13:03 +01:00
Dylan K. Taylor
148228e360 update pocketmine/math, adapt to add() changes 2020-05-19 12:26:18 +01:00
Dylan K. Taylor
58fb185e05 Merge commit '58e32086c04d6622c01f59d0cd7216bd8a50eddb'
# Conflicts:
#	resources/vanilla
#	src/world/World.php
2020-05-18 10:47:37 +01:00
Dylan K. Taylor
11ef9fb0c0 Item-from-string parsing no longer depends on ItemIds
after this is done I'm banning the constant() function.
2020-05-13 00:18:49 +01:00
Dylan K. Taylor
8efe7fcfb0 World: allow configuring blocks-per-tick for random updating
this makes it much easier to observe and debug stuff that depends on it, such as grass, crop and tree growth, since they'll happen much faster.
A future improvement would be to have the update function use a non-global random so that the output can be reproduced using a given seed.
2020-05-10 11:50:31 +01:00