zazsona / decorheads Goto Github PK
View Code? Open in Web Editor NEWServer-side Minecraft plugin for Bukkit/Spigot adding naturally appearing and craftable heads into your world, including support to add your own!
License: MIT License
Server-side Minecraft plugin for Bukkit/Spigot adding naturally appearing and craftable heads into your world, including support to add your own!
License: MIT License
At the moment, DecorHeads stores a single JSON file for tracking placed head data. Inevitably, as this file grows read/write operations will become more taxing.
The preposition is to separate this file on a per-chunk basis. This comes with two benefits:
Requirements:
I'm having a huge issue when players place heads. When doing so, the chat is filled with a big chunk of text in chat for everyone to see. Could there be any possible remedy for this?
Along side these screenshots, I will also provide a list of each plugin installed:
As well as the chunk of text that appears in console after placing a head:
09.02 02:48:14 [Server] INFO Item: ItemStack{PLAYER_HEAD x 1, SKULL_META:{meta-type=SKULL, display-name={"extra":[{"text":"Beer"}],"text":""}, lore=[{"extra":[{"bold":false,"italic":false,"underlined":false,"strikethrough":false,"obfuscated":false,"color":"blue","text":"DecorHeads"}],"text":""}], internal=H4sIAAAAAAAA/02PS06DUBhGfw0miC7EiQkPi+nMWk17SfmxlPdISm/lcW9tKDS9LMGdODAapy7DFRg3IkOH55xv8ikACpwvqpaxh/p5XTAqg4QppyDdUloroPR6S+umoLtTkBt6aNqa7hQAOJLhJEhZS+GdCktNolxdRRbLBDF79hYqc0i5vSabQCzHxCS879ORORPDf9tBk4YDFhtWnmzm7ZIH6sxwGZ26Wsb9Pd6NNFv3BZZPOupWgV6m2V3OHC+7crz7DnW3iDnpXWbgxD84k6CKvYQnYazZIRY2D6qknAvkpMOO6Di2hutIBTiDY7LqP0gvlz9fr58OfPx+P77diAuAP4hnvAYSAQAA, PublicBukkitValues={decorheads:headkey=beer}, skull-owner=Beer}}
Thank you!
I just noticed that when any user is online, the Console gets spammed with this stuff:
Occasionally, there's a mention of DecorHeads Could not pass event BlockFromToEvent to DecorHeads v2.3.0
so I tried disabling the plugin and the spam stops. This was a lovely plugin, and I'm no coder so I don't know if there's some conflict somewhere with another plugin I added or if there's some setting I need to fix, but it renders Console unusable so I'm keeping it disabled for now.
This spam showed up recently, after I updated from the 2.2.0 to 2.3.0 release. The only other plugin I added around the time the spam started was a legacy NickNames plugin (which shouldn't have any conflicts) and updated my HuskHomes version to 3.0.1.
Of note: When I first noticed the spam, it wasn't so much spam as the occasional line and sometimes the Could not pass event BlockFromToEvent to DecorHeads v2.3.0
- I thought maybe this was because we were playing in 1.19.2 but I hadn't updated DecorHeads to 2.3.1. But last night, when I was checking something for a player, Console was flooded with these lines and I couldn't do anything in Console before it disappeared in the history. I just tried updating from 2.3.0 to 2.3.1 and the problem persists.
Hi! So sorry to bother you again, but I'm running a new server and I wanted to install DecorHeads. However, when I try to restart the server with DecorHeads installed, these issues pop up and none of the heads are recognized. Can you help me figure out what is wrong, and how to fix it? I have tried redownloading and replacing the .jar file, but it hasn't worked. The server is on 1.19.1, and I can supply any other information if you need it. Thank you so much!
02.04 21:33:26 [Server] WARN Cannot read field "value" because "anotherString" is null 02.04 21:33:26 [Server] WARN java.lang.NullPointerException: Cannot read field "value" because "anotherString" is null 02.04 21:33:26 [Server] WARN at java.base/java.lang.String.compareTo(String.java:2012) 02.04 21:33:26 [Server] WARN at DecorHeads.jar//com.zazsona.decorheads.config.HeadUpdater.getUpdates(HeadUpdater.java:89) 02.04 21:33:26 [Server] WARN at DecorHeads.jar//com.zazsona.decorheads.config.HeadUpdater.updateHeadsFile(HeadUpdater.java:44) 02.04 21:33:26 [Server] WARN at DecorHeads.jar//com.zazsona.decorheads.Core.onEnable(Core.java:35) 02.04 21:33:26 [Server] WARN at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:264) 02.04 21:33:26 [Server] WARN at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:370) 02.04 21:33:26 [Server] WARN at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:542) 02.04 21:33:26 [Server] WARN at org.bukkit.craftbukkit.v1_19_R1.CraftServer.enablePlugin(CraftServer.java:563) 02.04 21:33:26 [Server] WARN at org.bukkit.craftbukkit.v1_19_R1.CraftServer.enablePlugins(CraftServer.java:477) 02.04 21:33:26 [Server] WARN at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:636) 02.04 21:33:26 [Server] WARN at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:422) 02.04 21:33:26 [Server] WARN at net.minecraft.server.dedicated.DedicatedServer.e(DedicatedServer.java:306) 02.04 21:33:26 [Server] WARN at net.minecraft.server.MinecraftServer.v(MinecraftServer.java:1124) 02.04 21:33:26 [Server] WARN at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:305) 02.04 21:33:26 [Server] WARN at java.base/java.lang.Thread.run(Thread.java:833)
There's no errors to show what goes wrong with this but apparently as soon as this plugin is installed Slimefun4 cargo monitors, generators, etc can no longer be dropped when broken in survival
Discovered a dupe when using DecorHeads along with Towny (and likely other land management plugins).
Player A is the mayor of the town, Venice. As mayor, they have access to place and break blocks in their town. Player A obtains a head and places it in their town.
Player B is the mayor of another town. They do not have access to place or break blocks in Venice. When Player B attempts to break the head that Player A placed earlier, the head stays there and does not break. However, a head drops like Player B really did break the head.
You can probably see where this is going. Player B can try to break the head over and over to drop unlimited amounts of heads.
Other Issue we've found is with the /dhwiki command. Not a critical issue per se, but console spam is never nice :P
Running the command without anything else specified throws an IndexOutOfBoundsException and tunning the command with a wrong/mistyped submenu throws an IllegalArgumentException
[20:04:35 WARN]: java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
[20:04:35 WARN]: at com.zazsona.decorheads.command.WikiCommand.onCommand(WikiCommand.java:41)
[20:04:35 WARN]: at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45)
[20:04:35 WARN]: at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:172)
[20:04:35 WARN]: at org.bukkit.craftbukkit.v1_17_R1.CraftServer.dispatchCommand(CraftServer.java:821)
[20:04:35 WARN]: at net.minecraft.server.network.PlayerConnection.handleCommand(PlayerConnection.java:2309)
[20:04:35 WARN]: at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:2120)
[20:04:35 WARN]: at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:2101)
[20:04:35 WARN]: at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:46)
[20:04:35 WARN]: at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:6)
[20:04:35 WARN]: at net.minecraft.network.protocol.PlayerConnectionUtils.lambda$ensureRunningOnSameThread$1(PlayerConnectionUtils.java:56)
[20:04:35 WARN]: at net.minecraft.server.TickTask.run(TickTask.java:18)
[20:04:35 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.executeTask(IAsyncTaskHandler.java:149)
[20:04:35 WARN]: at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.executeTask(IAsyncTaskHandlerReentrant.java:23)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.executeTask(MinecraftServer.java:1422)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.executeTask(MinecraftServer.java:190)
[20:04:35 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.executeNext(IAsyncTaskHandler.java:122)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.bf(MinecraftServer.java:1400)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.executeNext(MinecraftServer.java:1393)
[20:04:35 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.awaitTasks(IAsyncTaskHandler.java:132)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.sleepForTick(MinecraftServer.java:1369)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.x(MinecraftServer.java:1280)
[20:04:35 WARN]: at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:319)
[20:04:35 WARN]: at java.base/java.lang.Thread.run(Unknown Source)
[20:03:54 WARN]: java.lang.IllegalArgumentException: Unknown submenu: test
[20:03:54 WARN]: at com.zazsona.decorheads.command.WikiCommand.onCommand(WikiCommand.java:49)
[20:03:54 WARN]: at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45)
[20:03:54 WARN]: at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:172)
[20:03:54 WARN]: at org.bukkit.craftbukkit.v1_17_R1.CraftServer.dispatchCommand(CraftServer.java:821)
[20:03:54 WARN]: at net.minecraft.server.network.PlayerConnection.handleCommand(PlayerConnection.java:2309)
[20:03:54 WARN]: at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:2120)
[20:03:54 WARN]: at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:2101)
[20:03:54 WARN]: at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:46)
[20:03:54 WARN]: at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:6)
[20:03:54 WARN]: at net.minecraft.network.protocol.PlayerConnectionUtils.lambda$ensureRunningOnSameThread$1(PlayerConnectionUtils.java:56)
[20:03:54 WARN]: at net.minecraft.server.TickTask.run(TickTask.java:18)
[20:03:54 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.executeTask(IAsyncTaskHandler.java:149)
[20:03:54 WARN]: at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.executeTask(IAsyncTaskHandlerReentrant.java:23)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.executeTask(MinecraftServer.java:1422)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.executeTask(MinecraftServer.java:190)
[20:03:54 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.executeNext(IAsyncTaskHandler.java:122)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.bf(MinecraftServer.java:1400)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.executeNext(MinecraftServer.java:1393)
[20:03:54 WARN]: at net.minecraft.util.thread.IAsyncTaskHandler.awaitTasks(IAsyncTaskHandler.java:132)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.sleepForTick(MinecraftServer.java:1369)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.x(MinecraftServer.java:1280)
[20:03:54 WARN]: at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:319)
[20:03:54 WARN]: at java.base/java.lang.Thread.run(Unknown Source)
(Just luckperms and decorheads installed, running MC1.17.1 purpur-1285)
As before, let me know if you need any more information.
The decorheads plugin is currently spamming my server's console with these errors.
- [Sat 11:16:37 ERROR Minecraft] Could not pass event BlockPistonExtendEvent to DecorHeads v2.3.0 java.lang.NullPointerException: Cannot invoke "java.util.HashMap.get(Object)" because "this.blockMeta" is null at DecorHeads.jar//com.zazsona.decorheads.blockmeta.BlockMetaLogger.isMetadataSet(BlockMetaLogger.java:89) at DecorHeads.jar//com.zazsona.decorheads.blockmeta.BlockMetaLogger.isMetadataSet(BlockMetaLogger.java:102) at DecorHeads.jar//com.zazsona.decorheads.blockmeta.BlockMetaLogger.isMetadataSet(BlockMetaLogger.java:108) at DecorHeads.jar//com.zazsona.decorheads.blockmeta.BlockInventoryOwnerListener.onPistonExtend(BlockInventoryOwnerListener.java:124) at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor52.execute(Unknown Source) at org.bukkit.plugin.EventExecutor.lambda$create$1(EventExecutor.java:75) at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:671) at net.minecraft.world.level.block.piston.BlockPiston.a(BlockPiston.java:392) at net.minecraft.world.level.block.piston.BlockPiston.a(BlockPiston.java:222) at net.minecraft.world.level.block.state.BlockBase$BlockData.a(BlockBase.java:949) at net.minecraft.server.level.WorldServer.a(WorldServer.java:1771) at net.minecraft.server.level.WorldServer.ar(WorldServer.java:1757) at net.minecraft.server.level.WorldServer.a(WorldServer.java:653) at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1619) at net.minecraft.server.dedicated.DedicatedServer.b(DedicatedServer.java:522) at net.minecraft.server.MinecraftServer.a(MinecraftServer.java:1482) at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1246) at net.minecraft.server.MinecraftServer.lambda$spin$1(MinecraftServer.java:320) at java.base/java.lang.Thread.run(Thread.java:833)
It started after my server experienced a crash so perhaps it's caused by some corrupt data?
Hey!
We've been using 2.0.0 on our server for a few days now, it works great, except 2 issues. (I'll put the second problem in another github issue)
This first one is that playerheads just don't drop when they get killed, even when explicitly setting the DecorHeads.DropHeads permission to true.
I also tested this with just decorheads and luckperms installed, so it shouldn't be a plugin incompatibility.
Currently running MC 1.17.1 on a paper fork (purpur-1285)
I don't really have more info to tell you I guess, feel free to let me know if you need something :)
So here I am again ^_^
Weird bug, haven't had the time to test this but I've seen it happening on my server.
It seems that when a player breaks a placed pre 2.0.0 head they don't drop an item, but only if placed on the floor!
Placing them on the wall and then breaking works fine.
(I'm assuming it's pre 2.0.0 heads, they have different NBT data than the current ones, I'll verify this later at some point. Unless you fix it beforehand :P)
Dunno if It is supposed to be that way. but an update a while ago made the heads stop stacking. I use it on my sub server and the admins and I thought it would change back, but it hasnt. getting to the point that we may need to remove them.
Hello! A friend of mine is hosting a 1.19 server and using your plugin, where it works perfectly fine. However, when they used a heads.yml file (headstxt.txt since github won't let me attach a .yml) that I customized, the plugin breaks and none of the heads appear in the world, even the non-modified heads. I checked the wiki and my file to see if there were any plugin-breaking mistakes, and I don't think that there are any. Did I miss something, and what can I do to make these custom heads work?
I have added mini blocks for all the shulker boxes to the heads.yml in the following manner:
mini-gray-shulker-box:
name: Mini Gray Shulker Box
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGM5MzYzNzhmN2IxYTcyYWM2NWI2YTI2YmY4NDZhZWNhMWVjZWYxZDlhMTVhNmJjYWJiODgyMmM4NTVmZWJhIn19fQ==
sources:
default-drop-0:
source-type: MINE_DROP
blocks:
- GRAY_SHULKER_BOX
drop-rate: 100
default-drop-1:
source-type: CRAFT_DROP
recipe-results:
- GRAY_SHULKER_BOX
drop-rate: 100
The drop rates are at 100% just to make sure that the block is set up correctly. Breaking a colored shulker box works great and it gives a head drop all the time. However, crafting a colored shulker box does nothing.
Using the sources page of the wiki, I can confirm that the source is registered correctly. It says it should give the block 100% of the time when crafting the colored shulker box. Despite this info showing correctly, the plugin doesn't actually give the head when crafting.
I have added other heads as well today using the source type CRAFT_DROP in this same format and they all worked as they should. This leads me to assume there might be an issue with picking up the craft event for shulker boxes. But that's just my hypothesis.
Hopefully this issue can be fixed, so that the plugin works as advertised!
Cause is likely due to generating player heads from an OfflinePlayer instance returning Base64 texture data with timestamp and profile data pertaining to the offline profile, which is reloaded every reboot/player reconnect:
{
"timestamp" : X,
"profileId" : "Y",
"profileName" : "Z",
"signatureRequired" : true,
"textures" : {
"SKIN" : {
"url" : "foo"
}
}
}
For consistent stacking, only the texture field should be loaded, as with "decor" heads:
{
"textures" : {
"SKIN" : {
"url" : "foo"
}
}
}
However, this disables the ability of the head to update with the player's skin. As such, there are two approaches:
Hey!
Not sure if you've seen this before but decorheads throws some errors into the server console at times (assuming when somebody breaks a head, haven't had the time to test yet).
Full error here, seems like it's trying to parse float from a string that isn't set:
[13:29:39 ERROR]: Could not pass event BlockBreakEvent to DecorHeads v1.5.1 java.lang.NumberFormatException: For input string: "null" at jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054) ~[?:?] at jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) ~[?:?] at java.lang.Double.parseDouble(Double.java:543) ~[?:?] at com.zazsona.decorheads.Settings.getDropChance(Settings.java:89) ~[?:?] at com.zazsona.decorheads.HeadDropListener.dropHead(HeadDropListener.java:288) ~[?:?] at com.zazsona.decorheads.HeadDropListener.checkGlobalBlockDrops(HeadDropListener.java:77) ~[?:?] at com.zazsona.decorheads.HeadDropListener.onBlockBreak(HeadDropListener.java:48) ~[?:?] at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor71.execute(Unknown Source) ~[?:?] at org.bukkit.plugin.EventExecutor.lambda$create$1(EventExecutor.java:69) ~[patched_1.16.5.jar:git-Purpur-1078] at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[patched_1.16.5.jar:git-Purpur-1078] at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[patched_1.16.5.jar:git-Purpur-1078] at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:607) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PlayerInteractManager.breakBlock(PlayerInteractManager.java:392) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PlayerInteractManager.a(PlayerInteractManager.java:345) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PlayerInteractManager.a(PlayerInteractManager.java:305) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PlayerConnection.a(PlayerConnection.java:1765) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PacketPlayInBlockDig.a(SourceFile:40) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PacketPlayInBlockDig.a(SourceFile:10) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.PlayerConnectionUtils.lambda$ensureMainThread$1(PlayerConnectionUtils.java:55) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.TickTask.run(SourceFile:18) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.IAsyncTaskHandler.executeTask(IAsyncTaskHandler.java:136) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.IAsyncTaskHandlerReentrant.executeTask(SourceFile:23) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.IAsyncTaskHandler.executeNext(IAsyncTaskHandler.java:109) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.MinecraftServer.bb(MinecraftServer.java:1335) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.MinecraftServer.executeNext(MinecraftServer.java:1328) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.IAsyncTaskHandler.awaitTasks(IAsyncTaskHandler.java:119) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.MinecraftServer.sleepForTick(MinecraftServer.java:1304) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.MinecraftServer.w(MinecraftServer.java:1148) ~[patched_1.16.5.jar:git-Purpur-1078] at net.minecraft.server.v1_16_R3.MinecraftServer.lambda$a$0(MinecraftServer.java:291) ~[patched_1.16.5.jar:git-Purpur-1078] at java.lang.Thread.run(Thread.java:834) [?:?]
Let me know if you need any other information
All in the title, it seems that when a head is placed on a wall it does not drop. Following the fix for #7, a head now drops but lacks metadata.
Seems as though one or both of BlockPlacedEvent and BlockBreakEvent do not fire for heads placed on walls.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.