Skip to content

Commit 8f460a0

Browse files
committed
[ChunkDataThrottle] Migrate to nms registry, vanilla blockstate occlude cache
1 parent ca5f35f commit 8f460a0

File tree

8 files changed

+655
-644
lines changed

8 files changed

+655
-644
lines changed

bukkit/src/main/kotlin/io/github/rothes/esu/bukkit/module/NetworkThrottleModule.kt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.github.rothes.esu.bukkit.util.version.adapter.nms.MCRegistryValueSeria
55
import io.github.rothes.esu.bukkit.util.version.versioned
66
import io.github.rothes.esu.core.configuration.ConfigLoader
77
import io.github.rothes.esu.core.configuration.ConfigurationPart
8+
import io.github.rothes.esu.core.configuration.LoadedConfiguration
89
import io.github.rothes.esu.core.module.configuration.BaseModuleConfiguration
910
import io.github.rothes.esu.lib.configurate.yaml.YamlConfigurationLoader
1011
import java.util.*
@@ -36,14 +37,26 @@ object NetworkThrottleModule: BukkitModule<BaseModuleConfiguration, NetworkThrot
3637
if (MCRegistryValueSerializers.isSupported) {
3738
builder.defaultOptions { options ->
3839
options.serializers { builder ->
39-
builder.register(
40-
MCRegistryValueSerializers.instance.entityType
41-
)
40+
builder.register(MCRegistryValueSerializers.instance.block)
41+
.register(MCRegistryValueSerializers.instance.entityType)
4242
}
4343
}
4444
}
4545
}
4646

47+
override fun preprocessConfig(loadedConfiguration: LoadedConfiguration) {
48+
// v0.12.4
49+
val node = loadedConfiguration.node
50+
val from = node.node("chunk-data-throttle")
51+
val to = node.node("chunk-data-throttle", "chunk-handler")
52+
for ((key, value) in from.childrenMap()) {
53+
if (key != "enabled" && key != "chunk-handler") {
54+
to.node(value.key()).from(value)
55+
from.removeChild(key)
56+
}
57+
}
58+
}
59+
4760

4861
data class ModuleData(
4962
val originalViewDistance: MutableMap<UUID, Int> = linkedMapOf(),
Lines changed: 7 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.github.rothes.esu.bukkit.module.networkthrottle
22

3-
import io.github.retrooper.packetevents.util.SpigotConversionUtil
43
import io.github.rothes.esu.bukkit.module.networkthrottle.chunkdatathrottle.ChunkDataThrottleHandler
54
import io.github.rothes.esu.bukkit.plugin
65
import io.github.rothes.esu.bukkit.util.ServerCompatibility
@@ -9,23 +8,20 @@ import io.github.rothes.esu.bukkit.util.version.versioned
98
import io.github.rothes.esu.core.command.annotation.ShortPerm
109
import io.github.rothes.esu.core.configuration.data.MessageData.Companion.message
1110
import io.github.rothes.esu.core.configuration.meta.Comment
12-
import io.github.rothes.esu.core.configuration.meta.RenamedFrom
13-
import io.github.rothes.esu.core.configuration.serializer.MapSerializer.DefaultedLinkedHashMap
1411
import io.github.rothes.esu.core.module.CommonFeature
1512
import io.github.rothes.esu.core.module.Feature
1613
import io.github.rothes.esu.core.module.configuration.BaseFeatureConfiguration
1714
import io.github.rothes.esu.core.module.configuration.EmptyConfiguration
1815
import io.github.rothes.esu.core.user.User
19-
import io.github.rothes.esu.lib.configurate.objectmapping.meta.PostProcess
20-
import org.bukkit.Material
2116
import org.incendo.cloud.annotations.Command
2217

2318
object ChunkDataThrottle: CommonFeature<ChunkDataThrottle.FeatureConfig, EmptyConfiguration>() {
2419

25-
val versioned by lazy { ChunkDataThrottleHandler::class.java.versioned() }
26-
val counter
27-
get() = versioned.counter
28-
private var wasEnabled = false
20+
val handler by lazy { ChunkDataThrottleHandler::class.java.versioned() }
21+
22+
init {
23+
if (ServerCompatibility.serverVersion >= "1.18") registerFeature(handler)
24+
}
2925

3026
override fun checkUnavailable(): Feature.AvailableCheck? {
3127
return super.checkUnavailable() ?: checkPacketEvents() ?: let {
@@ -37,161 +33,23 @@ object ChunkDataThrottle: CommonFeature<ChunkDataThrottle.FeatureConfig, EmptyCo
3733
}
3834
}
3935

40-
override fun onReload() {
41-
super.onReload()
42-
if (enabled)
43-
versioned.onReload()
44-
}
45-
4636
override fun onEnable() {
47-
wasEnabled = true
48-
versioned.onEnable()
49-
5037
registerCommands(object {
5138
@Command("esu networkThrottle chunkDataThrottle stats")
5239
@ShortPerm("chunkDataThrottle")
5340
fun chunkDataThrottleView(sender: User) {
54-
val (minimalChunks, resentChunks, resentBlocks) = counter
41+
val (minimalChunks, resentChunks, resentBlocks) = handler.counter
5542
sender.message("minimalChunks: $minimalChunks ; resentChunks: $resentChunks ; resentBlocks: $resentBlocks")
5643
}
5744
})
5845
}
5946

60-
override fun onTerminate() {
61-
super.onTerminate()
62-
if (wasEnabled) versioned.onTerminate()
63-
}
64-
6547
@Comment("""
6648
Helps to reduce chunk upload bandwidth. Plugin will compress invisible blocks in chunk data packet.
6749
If necessary, we send a full chunk data again.
6850
This can save about 50% bandwidth usage in overworld and 30% in nether averagely.
6951
Make sure you have enabled network-compression on proxy or this server.
7052
""")
71-
data class FeatureConfig(
72-
@Comment("""
73-
Plugin will resent complete original chunk data if resent block amount exceeds this value.
74-
Set it to -1 will never resent chunk but keep updating nearby blocks,
75-
0 to always resent original chunks.
76-
Set this to a large value can prevent constantly sending block update packets.
77-
Original chunk is not with anti-xray functionality. It is recommended to leave this value -1 .
78-
""",
79-
overrideOld = [
80-
"""
81-
Plugin will resent whole chunk data if resent block amount exceeds this value.
82-
Set it to -1 will never resent chunk but keep updating nearby blocks,
83-
0 to always resent chunks.
84-
"""
85-
])
86-
val thresholdToResentWholeChunk: Int = -1,
87-
@Comment("""
88-
We updates the nearby blocks when a player digs a block immediately.
89-
If this is enabled, we will check if the block is in the interaction range
90-
of the player with a rough calculation.
91-
""")
92-
val updateOnLegalInteractOnly: Boolean = true,
93-
@Comment("How many distance of blocks to update from the center when necessary.")
94-
val updateDistance: Int = 2,
95-
@Comment("""
96-
The bedrock level(minimal height) is never visible unless you are in void.
97-
We would skip the check, and if you don't like it you can enable it.
98-
""")
99-
val minimalHeightInvisibleCheck: Boolean = false,
100-
@Comment("""
101-
Same with minimal-height but it's for nether roof. For out-of-the-box, it's true by default.
102-
It's highly recommend to set it to FALSE if you don't allow players to get above there.
103-
""",
104-
overrideOld = ["Same with minimal-height but it's for nether roof."]
105-
)
106-
val netherRoofInvisibleCheck: Boolean = true,
107-
@Comment("""
108-
If a non-occluding block is surrounded by occluding blocks, the center block is invisible.
109-
But should we consider all surrounded blocks invisible to this block face?
110-
Unless the player joins the game with their eye in the non-occluding block,
111-
they will never naturally see those surrounded blocks.
112-
This step takes extra ~0.02ms, so it's not enabled by default.
113-
Enable this could help with saving bandwidth in nether, as there's many single-block lava.
114-
""")
115-
val detectInvisibleSingleBlock: Boolean = false,
116-
@Comment("""
117-
Detect lava pool, and consider lava blocks which being covered invisible.
118-
This step takes extra ~0.03ms, so it's not enabled by default.
119-
It also makes the plugin detect nearby blocks everytime player moves.
120-
Enable this could help with saving bandwidth, especially in nether.
121-
""")
122-
val detectLavaPool: Boolean = false,
123-
@RenamedFrom("single-valued-section-block-list")
124-
@Comment("""
125-
This feature doesn't support running along with any other anti-xray plugins.
126-
You must use the anti-xray here we provide.
127-
128-
We will send non-visible blocks to one of the random block in this list.
129-
If you don't like to anti-xray, you can set the list to 'bedrock'.
130-
""",
131-
overrideOld = ["Plugin will convert chunks with all non-visible blocks to single-valued palette format,\nThis could save a lot of bandwidth. And since we are conflicting with anti-xray things,\nyou can use this for some kind of substitution.\nWe choose a random block from the list and make it of a 16*16*16 chunk section."]
132-
)
133-
val antiXrayRandomBlockList: DefaultedLinkedHashMap<String, MutableList<Material>> = DefaultedLinkedHashMap<String, MutableList<Material>>(
134-
mutableListOf(Material.BEDROCK)
135-
).apply {
136-
put("world", buildList {
137-
val cavesUpdate = ServerCompatibility.serverVersion >= "1.17"
138-
add(Material.COAL_ORE)
139-
if (cavesUpdate) add(Material.COPPER_ORE)
140-
addAll(listOf(Material.IRON_ORE, Material.GOLD_ORE,
141-
Material.EMERALD_ORE, Material.DIAMOND_ORE, Material.REDSTONE_ORE, Material.LAPIS_ORE))
142-
143-
if (cavesUpdate) addAll(listOf(Material.DEEPSLATE_COAL_ORE, Material.DEEPSLATE_COPPER_ORE,
144-
Material.DEEPSLATE_IRON_ORE, Material.DEEPSLATE_GOLD_ORE, Material.DEEPSLATE_EMERALD_ORE,
145-
Material.DEEPSLATE_DIAMOND_ORE, Material.DEEPSLATE_REDSTONE_ORE, Material.DEEPSLATE_LAPIS_ORE))
146-
}.toMutableList())
147-
put("world_nether", buildList {
148-
add(Material.NETHER_QUARTZ_ORE)
149-
if (ServerCompatibility.serverVersion >= "1.16") {
150-
add(Material.NETHER_GOLD_ORE)
151-
add(Material.ANCIENT_DEBRIS)
152-
}
153-
}.toMutableList())
154-
put("world_the_end", mutableListOf(Material.END_STONE))
155-
},
156-
@Comment("""
157-
If enabled, we add a extra block type to chunk section palettes for the random block.
158-
This will greatly enhance anti-xray capabilities while giving only few bytes of additional bandwidth.
159-
""")
160-
val enhancedAntiXray: Boolean = true,
161-
@Comment("""
162-
Put any blocks you don't want to hide, so they are ignored while processing.
163-
For example, you can add any ores to it, so there's no anti-xray effect.
164-
WARNING: This significantly reduces compression badly. Please make sure you really have to do this.
165-
""")
166-
val nonInvisibleBlocksOverrides: Set<Material> = setOf(),
167-
): BaseFeatureConfiguration(true) {
168-
169-
val antiXrayRandomBlockIds by lazy {
170-
with(antiXrayRandomBlockList) {
171-
DefaultedLinkedHashMap<String, IntArray>((default ?: listOf(Material.BEDROCK)).map { it.globalId }.toIntArray()).also {
172-
it.putAll(entries.map { it.key to it.value.map { it.globalId }.toIntArray() })
173-
}
174-
}
175-
}
176-
177-
private val Material.globalId
178-
get() = if (!this.isBlock) error("Material $this is not a block type!") else SpigotConversionUtil.fromBukkitBlockData(createBlockData()).globalId
179-
180-
@PostProcess
181-
private fun postProcess() {
182-
fun checkEmptyBlockList(key: String, list: MutableList<Material>) {
183-
if (list.isEmpty()) {
184-
list.add(Material.BEDROCK)
185-
plugin.warn("[ChunkDataThrottle] Anti-xray random block list of '$key' is empty! We have added bedrock to it.")
186-
}
187-
}
188-
antiXrayRandomBlockList.default?.let {
189-
checkEmptyBlockList("default", it)
190-
}
191-
antiXrayRandomBlockList.entries.toList().forEach {
192-
checkEmptyBlockList(it.key, it.value)
193-
}
194-
}
195-
}
53+
class FeatureConfig(): BaseFeatureConfiguration(true)
19654

19755
}

bukkit/src/main/kotlin/io/github/rothes/esu/bukkit/module/networkthrottle/chunkdatathrottle/ChunkDataThrottleHandler.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package io.github.rothes.esu.bukkit.module.networkthrottle.chunkdatathrottle
22

3-
interface ChunkDataThrottleHandler {
3+
import io.github.rothes.esu.core.module.CommonFeature
44

5-
val counter: Counter
5+
abstract class ChunkDataThrottleHandler<C, L>: CommonFeature<C, L>() {
66

7-
fun onEnable()
8-
fun onReload()
9-
fun onTerminate()
7+
override val name: String = "ChunkHandler"
8+
9+
val counter: Counter = Counter()
1010

1111
data class Counter(
1212
var minimalChunks: Long = 0,

bukkit/src/main/resources/lang/modules/NetworkThrottle/config.yml/zh_cn.yml

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,49 @@
33
# 平均可以节省约 50% 的主世界带宽使用量和 30% 的下界带宽使用量。
44
# 确保您已在群组服务器或本服务器上启用网络压缩(network-compression)。
55
chunk-data-throttle:
6-
# 如果重新发送的方块数量超过此值,将直接重新发送整个区块的完整原始数据。
7-
# 设置为 -1 表示永远不会重新发送整个区块,而是持续更新相邻方块;
8-
# 设置为 0 表示始终重新发送完整的原始区块。
9-
# 设置为较大的值可以避免持续发送方块更新数据包,但尚未确定是否有益。
10-
# 此外,原始区块不会包含假矿功能。建议保留为 -1 。
11-
threshold-to-resent-whole-chunk:
12-
# 当玩家开始挖掘一个方块时,我们会立即更新相邻的方块。
13-
# 如果启用此选项,我们将通过粗略计算来检查该方块是否在玩家的合法交互范围内。
14-
update-on-legal-interact-only:
15-
# 每次更新方块时,更新多少距离内的相邻方块。
16-
update-distance:
17-
# 除非身处虚空,否则基岩层(世界最小高度)永远不可见。
18-
# 默认我们会跳过这项检查,如果你不喜欢,可以启用。
19-
minimal-height-invisible-check:
20-
# 与 minimal-height 相似,适用于下界的基岩顶层. 为了开箱即用,默认为 true。
21-
# 如果您不允许玩家上基岩层,强烈建议将此选项设为 FALSE。
22-
nether-roof-invisible-check:
23-
# 如果一个透明方块被非透明方块包围,则明显中心方块不可见。
24-
# 此外,是否应该认为所有相邻的方块对于该方块面是不可见的?
25-
# 除非玩家加入游戏时视线在这个中心方块内,否则永远不会看到相邻方块。
26-
# 此步骤额外耗时约 0.02 毫秒,因此默认情况下不启用。
27-
# 启用此选项有助于节省下界的带宽,因为下界中有很多单方块的熔岩。
28-
detect-invisible-single-block:
29-
# 检测熔岩池,将被覆盖的熔岩方块视为不可见。
30-
# 此步骤额外耗时约 0.03 毫秒,因此默认情况下不启用。
31-
# 这还会要求插件在玩家每次移动时检测附近的方块。
32-
# 启用此功能有助于节省带宽,尤其是在下界。
33-
detect-lava-pool:
34-
# 此功能不支持与其他任何假矿插件同时运行。
35-
# 您必须使用我们提供的假矿功能。
36-
#
37-
# 我们会将不可见的方块替换为此列表中的随机一个方块。
38-
# 如果您不想启用假矿,可将列表设置为 'bedrock' 。
39-
anti-xray-random-block-list:
40-
# 若启用,在不增加子区块“调色板”位数时,可添加一个随机方块类型。
41-
# 可大幅增强假矿效果,同时仅占用额外少量字节的带宽。
42-
enhanced-anti-xray:
43-
# 在此列表中添加的任何方块在处理时会被忽略。
44-
# 可以添加任何不想被隐藏的方块。
45-
# 例如,你可以添加任何矿石,这样就不会产生反矿透效果。
46-
# *警告*:添加任何方块都可能严重降低带宽压缩率,请三思。
47-
non-invisible-blocks-overrides:
6+
chunk-handler:
7+
# 如果重新发送的方块数量超过此值,将直接重新发送整个区块的完整原始数据。
8+
# 设置为 -1 表示永远不会重新发送整个区块,而是持续更新相邻方块;
9+
# 设置为 0 表示始终重新发送完整的原始区块。
10+
# 设置为较大的值可以避免持续发送方块更新数据包,但尚未确定是否有益。
11+
# 此外,原始区块不会包含假矿功能。建议保留为 -1 。
12+
threshold-to-resent-whole-chunk:
13+
# 当玩家开始挖掘一个方块时,我们会立即更新相邻的方块。
14+
# 如果启用此选项,我们将通过粗略计算来检查该方块是否在玩家的合法交互范围内。
15+
update-on-legal-interact-only:
16+
# 每次更新方块时,更新多少距离内的相邻方块。
17+
update-distance:
18+
# 除非身处虚空,否则基岩层(世界最小高度)永远不可见。
19+
# 默认我们会跳过这项检查,如果你不喜欢,可以启用。
20+
minimal-height-invisible-check:
21+
# 与 minimal-height 相似,适用于下界的基岩顶层. 为了开箱即用,默认为 true。
22+
# 如果您不允许玩家上基岩层,强烈建议将此选项设为 FALSE。
23+
nether-roof-invisible-check:
24+
# 如果一个透明方块被非透明方块包围,则明显中心方块不可见。
25+
# 此外,是否应该认为所有相邻的方块对于该方块面是不可见的?
26+
# 除非玩家加入游戏时视线在这个中心方块内,否则永远不会看到相邻方块。
27+
# 此步骤额外耗时约 0.02 毫秒,因此默认情况下不启用。
28+
# 启用此选项有助于节省下界的带宽,因为下界中有很多单方块的熔岩。
29+
detect-invisible-single-block:
30+
# 检测熔岩池,将被覆盖的熔岩方块视为不可见。
31+
# 此步骤额外耗时约 0.03 毫秒,因此默认情况下不启用。
32+
# 这还会要求插件在玩家每次移动时检测附近的方块。
33+
# 启用此功能有助于节省带宽,尤其是在下界。
34+
detect-lava-pool:
35+
# 此功能不支持与其他任何假矿插件同时运行。
36+
# 您必须使用我们提供的假矿功能。
37+
#
38+
# 我们会将不可见的方块替换为此列表中的随机一个方块。
39+
# 如果您不想启用假矿,可将列表设置为 'bedrock' 。
40+
anti-xray-random-block-list:
41+
# 若启用,在不增加子区块“调色板”位数时,可添加一个随机方块类型。
42+
# 可大幅增强假矿效果,同时仅占用额外少量字节的带宽。
43+
enhanced-anti-xray:
44+
# 在此列表中添加的任何方块在处理时会被忽略。
45+
# 可以添加任何不想被隐藏的方块。
46+
# 例如,你可以添加任何矿石,这样就不会产生反矿透效果。
47+
# *警告*:添加任何方块都可能严重降低带宽压缩率,请三思。
48+
non-invisible-blocks-overrides:
4849

4950
# 启用动态区块发送速率。需要在 ESU 的 velocity 插件端也开启此功能。
5051
dynamic-chunk-send-rate:
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.github.rothes.esu.bukkit.util.version.adapter.nms
2+
3+
import net.minecraft.world.level.block.state.BlockState
4+
5+
interface BlockOccludeTester {
6+
7+
fun isFullOcclude(blockState: BlockState): Boolean
8+
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.github.rothes.esu.bukkit.util.version.adapter.nms.v1_17_1
2+
3+
import io.github.rothes.esu.bukkit.util.version.adapter.nms.BlockOccludeTester
4+
import io.github.rothes.esu.core.util.UnsafeUtils.usBooleanAccessor
5+
import io.github.rothes.esu.core.util.UnsafeUtils.usNullableObjAccessor
6+
import net.minecraft.world.level.block.state.BlockBehaviour
7+
import net.minecraft.world.level.block.state.BlockState
8+
9+
object BlockOccludeTesterImpl: BlockOccludeTester {
10+
11+
private val canOcclude = BlockBehaviour.BlockStateBase::class.java.getDeclaredField("canOcclude").usBooleanAccessor
12+
private val bsCache = BlockBehaviour.BlockStateBase::class.java.getDeclaredField("cache").usNullableObjAccessor
13+
14+
override fun isFullOcclude(blockState: BlockState): Boolean {
15+
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // No worries
16+
return canOcclude[blockState]
17+
&& bsCache[blockState] != null
18+
&& blockState.isCollisionShapeFullBlock(null, null)
19+
}
20+
21+
}

0 commit comments

Comments
 (0)