-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide a basic implementation of an entity rule manager
- Loading branch information
Showing
4 changed files
with
197 additions
and
18 deletions.
There are no files selected for viewing
140 changes: 140 additions & 0 deletions
140
paper/src/main/kotlin/com/noxcrew/noxesium/paper/api/EntityRuleManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package com.noxcrew.noxesium.paper.api | ||
|
||
import com.noxcrew.noxesium.paper.api.event.NoxesiumPlayerRegisteredEvent | ||
import com.noxcrew.noxesium.paper.api.network.clientbound.ClientboundSetExtraEntityDataPacket | ||
import com.noxcrew.noxesium.paper.api.rule.RemoteServerRule | ||
import io.papermc.paper.event.player.PlayerTrackEntityEvent | ||
import org.bukkit.Bukkit | ||
import org.bukkit.entity.Entity | ||
import org.bukkit.event.EventHandler | ||
import org.bukkit.event.HandlerList | ||
import org.bukkit.event.Listener | ||
import org.bukkit.event.entity.EntityRemoveEvent | ||
import java.util.WeakHashMap | ||
|
||
/** | ||
* Provides a simple implementation for changing entity rules on entities. | ||
* | ||
* This is not used internally, so you should use it as a reference implementation | ||
* to tweak yourself. Feel free to merge any improvements you make upstream. | ||
* | ||
* For reference, MCC uses a custom implementation of this baked into our own | ||
* fake entity system where we send all entities entirely through packets and manage | ||
* them custom, hence we do not need a system such as this. | ||
*/ | ||
public class EntityRuleManager(private val manager: NoxesiumManager) : Listener { | ||
|
||
private val entities = WeakHashMap<Entity, RuleHolder>() | ||
private var task: Int = -1 | ||
|
||
/** | ||
* Registers this manager. | ||
*/ | ||
public fun register() { | ||
Bukkit.getPluginManager().registerEvents(this, manager.plugin) | ||
|
||
// Send rule updates once a tick in a batch | ||
task = Bukkit.getScheduler().scheduleSyncRepeatingTask(manager.plugin, { | ||
for ((entity, holder) in entities) { | ||
if (!holder.needsUpdate) continue | ||
holder.markAllUpdated() | ||
|
||
// Send the packet to all players that can see it | ||
for (player in Bukkit.getOnlinePlayers()) { | ||
if (!player.canSee(entity)) continue | ||
manager.sendPacket(player, | ||
ClientboundSetExtraEntityDataPacket( | ||
entity.entityId, | ||
holder.rules | ||
// Only include rules that need to be updated! | ||
.filter { it.value.changePending } | ||
// Only include rules that are available to this player! | ||
.filter { manager.entityRules.isAvailable(it.key, manager.getProtocolVersion(player) ?: -1) } | ||
.ifEmpty { null } | ||
?.mapValues { (_, rule) -> | ||
{ buffer -> (rule as RemoteServerRule<Any>).write(rule.value, buffer) } | ||
} ?: continue | ||
) | ||
) | ||
} | ||
} | ||
}, 1, 1) | ||
} | ||
|
||
/** | ||
* Unregisters this manager. | ||
*/ | ||
public fun unregister() { | ||
HandlerList.unregisterAll(this) | ||
Bukkit.getScheduler().cancelTask(task) | ||
} | ||
|
||
/** Returns the given [rule] for [entity]. */ | ||
public fun <T : Any> getEntityRule(entity: Entity, rule: RuleFunction<T>): RemoteServerRule<T>? = | ||
getEntityRule(entity, rule.index) | ||
|
||
/** Returns the given [ruleIndex] for [entity]. */ | ||
public fun <T : Any> getEntityRule(entity: Entity, ruleIndex: Int): RemoteServerRule<T>? = | ||
entities.computeIfAbsent(entity) { RuleHolder() }.let { holder -> | ||
manager.entityRules.create(ruleIndex, holder) | ||
} | ||
|
||
/** | ||
* Send all entities' data when a player gets registered with Noxesium so | ||
* they can properly see entities that were sent to them already. | ||
*/ | ||
@EventHandler | ||
public fun onNoxesiumPlayerRegistered(e: NoxesiumPlayerRegisteredEvent) { | ||
val player = e.player | ||
val protocol = e.protocolVersion | ||
|
||
for ((entity, holder) in entities) { | ||
if (!player.canSee(entity)) continue | ||
manager.sendPacket(player, | ||
ClientboundSetExtraEntityDataPacket( | ||
entity.entityId, | ||
holder.rules | ||
// Only include rules that are available to this player! | ||
.filter { manager.entityRules.isAvailable(it.key, protocol) } | ||
.ifEmpty { null } | ||
?.mapValues { (_, rule) -> | ||
{ buffer -> (rule as RemoteServerRule<Any>).write(rule.value, buffer) } | ||
} ?: continue | ||
) | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* When an entity starts being shown to a player we | ||
* send its data along as well. | ||
*/ | ||
@EventHandler | ||
public fun onEntityShown(e: PlayerTrackEntityEvent) { | ||
val holder = entities[e.entity] ?: return | ||
val protocol = manager.getProtocolVersion(e.player) ?: return | ||
|
||
manager.sendPacket(e.player, | ||
ClientboundSetExtraEntityDataPacket( | ||
e.entity.entityId, | ||
holder.rules | ||
// Only include rules that are available to this player! | ||
.filter { manager.entityRules.isAvailable(it.key, protocol) } | ||
.ifEmpty { null } | ||
?.mapValues { (_, rule) -> | ||
{ buffer -> (rule as RemoteServerRule<Any>).write(rule.value, buffer) } | ||
} ?: return | ||
) | ||
) | ||
} | ||
|
||
/** | ||
* Remove data stored for an entity when the entity | ||
* gets removed. This also happens indirectly because we | ||
* use a WeakHashMap. | ||
*/ | ||
@EventHandler | ||
public fun onEntityRemoved(e: EntityRemoveEvent) { | ||
entities.remove(e.entity) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
paper/src/main/kotlin/com/noxcrew/noxesium/paper/api/event/NoxesiumPlayerRegisteredEvent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.noxcrew.noxesium.paper.api.event | ||
|
||
import org.bukkit.entity.Player | ||
import org.bukkit.event.HandlerList | ||
import org.bukkit.event.player.PlayerEvent | ||
|
||
/** Emitted by [NoxesiumManager] when it registers a new player. */ | ||
public class NoxesiumPlayerRegisteredEvent( | ||
player: Player, | ||
/** The new protocol version of the player. */ | ||
public val protocolVersion: Int, | ||
/** The raw version string of the player's installed Noxesium jar. */ | ||
public val version: String, | ||
) : PlayerEvent(player) { | ||
|
||
public companion object { | ||
@JvmStatic | ||
public val HANDLER_LIST: HandlerList = HandlerList() | ||
|
||
@JvmStatic | ||
public fun getHandlerList(): HandlerList = HANDLER_LIST | ||
} | ||
|
||
override fun getHandlers(): HandlerList = HANDLER_LIST | ||
} |