rvandoosselaer / blocks Goto Github PK
View Code? Open in Web Editor NEWA block (voxel) engine for jMonkeyEngine
License: BSD 3-Clause "New" or "Revised" License
A block (voxel) engine for jMonkeyEngine
License: BSD 3-Clause "New" or "Revised" License
Yes, its me again ^^
So I have been playing around with it a lot and have all my weird behavior fixed, except one: When a character jumps onto a block and hits the edge he gets launched in the air big time.
Steps to reproduce:
Walk up right in front of a block, press 'w' and hold it, then press 'space bar'
I have had a deeper look into the matter and it seems as if the velocity of the object increases a lot in the collision tick (4 to > 9), so I implemented a custom PhysicsTickListener, but that only solves the problem after each tick, so you can still feel the boost very well. If you want to enable my 'fix' remove the comment on line 46 in PhysicsTickHandler
Thank you for all your awesome support and all the work you are putting into this.
The values in the Direction enum are ambiguous.
The values should change to:
The names of the shapes should also be adapted to correspond with the new values.
Rename FluidDepthFilter to FluidFilter.
When adding shoreline effects and reflection, we do more then just simulate depth.
Probably the Chunk.isFaceVisible()
method would better to be public, needed for creating our own custom shapes. It probably makes sense to change Chunk.getNeighbour()
to public as well.
Add a contributing file with code guidelines, agreements, ...
The current water implementation has some serious drawbacks.
To make more realistic flowing water (liquid) a different technical solution should be worked out using cellular automata.
It will be nice to add a PBR version of the water material. :)
I am using the latest version of the blocks lib (1.6.3) and for some reason when running my code my player falls though a chunk.
I have PhysicsChunkPagerState physicsChunkPager = stateManager.getState(PhysicsChunkPagerState.class); physicsChunkPager.setLocation(new Vector3f(cam.getLocation()));
put in the simpleUpdate method and this: stateManager.attachAll(new ChunkManagerState(chunkManager), new ChunkPagerState(chunkNode, chunkManager), new PhysicsChunkPagerState(getPhysicsSpace(), chunkManager));
and this: BlocksConfig.getInstance().setPhysicsGrid(new Vec3i(3, 1, 3));
in my simpleInitApp method.
I suspect that it has to do with this piece of code which for some reason is different then the code on github:
If it helps, I here is my pom.xml file:
`
4.0.0
<groupId>org.example</groupId>
<artifactId>RamBlocks</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<jme3_g>org.jmonkeyengine</jme3_g>
<jme3_v>3.3.2-stable</jme3_v>
</properties>
<repositories>
<repository>
<id>jcenterJMonkey</id>
<url>https://dl.bintray.com/jmonkeyengine/org.jmonkeyengine</url>
</repository>
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
<repository>
<id>jcenterBlocks</id>
<url>https://dl.bintray.com/remyvd/rvandoosselaer</url>
</repository>
<repository>
<id>jcenterMathAndLemur</id>
<url>https://dl.bintray.com/simsilica/Sim-tools/</url>
</repository>
<repository>
<id>jcenterMinie</id>
<url>https://dl.bintray.com/stephengold/com.github.stephengold/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>${jme3_g}</groupId>
<artifactId>jme3-core</artifactId>
<version>${jme3_v}</version>
</dependency>
<dependency>
<groupId>${jme3_g}</groupId>
<artifactId>jme3-desktop</artifactId>
<version>${jme3_v}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${jme3_g}</groupId>
<artifactId>jme3-effects</artifactId>
<version>${jme3_v}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${jme3_g}</groupId>
<artifactId>jme3-lwjgl</artifactId>
<version>${jme3_v}</version>
</dependency>
<dependency>
<groupId>${jme3_g}</groupId>
<artifactId>jme3-testdata</artifactId>
<version>${jme3_v}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.rvandoosselaer</groupId>
<artifactId>blocks</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>com.simsilica</groupId>
<artifactId>sim-math</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.github.stephengold</groupId>
<artifactId>Minie</artifactId>
<version>3.1.0-test2</version>
</dependency>
<dependency>
<groupId>com.simsilica</groupId>
<artifactId>lemur</artifactId>
<version>1.14.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.6</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.jayfella</groupId>
<artifactId>jme-fastnoise</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
<version>1.4.5-12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.voidcitymc.blocks.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Thank you :)
I would suggest not register default blocks, types, shapes in the registry constructor and let the user code call this if he wants. For example, in my case, I do not use the default ones and I am adding my own blocks.
Blocks/src/main/java/com/rvandoosselaer/blocks/BlockRegistry.java
Lines 32 to 34 in 4528e17
Blocks/src/main/java/com/rvandoosselaer/blocks/ShapeRegistry.java
Lines 33 to 35 in 4528e17
Blocks/src/main/java/com/rvandoosselaer/blocks/TypeRegistry.java
Lines 52 to 57 in 4528e17
I know I can use the clear()
method to remove them but I want them to not get registered in the first place :)
(I mean loading all those textures,... would be a waste If I am going to clear them after)
Please let me know if you agree with this proposal and I will submit a PR if you want.
In my project, I'm trying to resolve a compatibility issue between two systems, and the best way I can think to do this was by making a child class of Chunk
, but I can't because it has a private constructor.
I don't understand why it has to have a private constructor though, because you could just make the constructor have all the code from createAt
and re-write createAt
to just feed the location into the constructor for backward compatibility.
So why don't you do that?
Add more blocks:
The dependency import for sim-math is incorrectly set to implementation
in the build.gradle
file.
This should be changed to api
so the dependency is also available for users using blocks.
This isn't an issue per se, but I don't really know where else to put this as there isn't a community forum for this project.
I'm trying to integrate this library into a pre-existing block data structure which has a feature where it can store arbitrary block data that may change the block's model. I've already written a basic adapter and I am not trying to store this data in the render blocks themselves, but I need a way of conforming this multi-model system into your single-model system at runtime.
How would you recommend doing this in a way that makes sense?
There is no way to download the module as a dependency
The registries (BlockRegistry, TypeRegistry, ShapeRegistry) have methods to return the full registry: BlockRegistry#getAll(), TypeRegistry#getAll(), ShapeRegistry#getAll().
For now they just return the keyset of the backing map. This should be changed so a read-only view of the keyset is returned to avoid (unwanted) tampering with the set.
The TypeRegistry
will be adapted to make it more easy to use custom created materials. It will however still be simple to change or update a texture of a block.
The current solution always uses the same material (Blocks/Materials/default-block.j3m
) based on the Lighting.j3md
material definition. Textures are loaded from the theme folder and set on the material. This way it's easy to change textures, but it's not possible to use other materials that are not based on the Lighting.j3md
material definition. This way PBR is not supported for example.
When a material file is found in the theme's folder, it should be used for that type. When there is no material file found, the old behavior should remain. In this case, the default material (Blocks/Materials/default-block.j3m
) will be used and the textures in the theme's folder will be loaded.
Another 'quality of life' update is to let the TypeRegistry
automatically pack textures together. Now you still need to use an image editor to combine the top, side and bottom textures into one texture. When you supply the 3 textures (top, side, bottom) in the theme's folder instead of the already combined one, the TypeRegistry
will combine them and set them on the default material.
Will appreciate if you can also update the BlockBuilder example to work with different block scales. When setting block scale other than 1 editor does not behave as expected.
Edit:
I guess these methods in ChunkManager :
getChunkLocation()
getBlockLocation()
getNeighbourBlockLocation()
addBlock()
removeBlock()
need to take the block scale into account when finding chunk/block location Vec3i? 🤔
See forum post.
Create a debug state that renders a settings panel to change and finetune the FluidFilter settings.
Minie v1.6 is released. Upgrade the library to the latest version.
Since Bintray has shutdown the information on the wiki to resolve Blocks is outdated.
See #65
SEVERE: Uncaught exception thrown in Thread[jME3 Main,6,main]
java.lang.NoSuchMethodError: java.nio.FloatBuffer.flip()Ljava/nio/FloatBuffer;
at com.rvandoosselaer.blocks.ChunkMesh.vector3fToBuffer(ChunkMesh.java:76)
at com.rvandoosselaer.blocks.ChunkMesh.generateMesh(ChunkMesh.java:44)
at com.rvandoosselaer.blocks.FacesMeshGenerator.createGeometry(FacesMeshGenerator.java:178)
at com.rvandoosselaer.blocks.FacesMeshGenerator.lambda$createNode$1(FacesMeshGenerator.java:72)
at java.util.HashMap.forEach(HashMap.java:1289)
at com.rvandoosselaer.blocks.FacesMeshGenerator.createNode(FacesMeshGenerator.java:71)
at com.rvandoosselaer.blocks.Chunk.createNode(Chunk.java:165)
at org.scaffoldeditor.editor.editor3d.block.WorldManager.loadWorld(WorldManager.java:29)
at org.scaffoldeditor.editor.editor3d.EditorApp.reload(EditorApp.java:91)
at org.scaffoldeditor.editor.editor3d.EditorApp.simpleInitApp(EditorApp.java:67)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:239)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:132)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:213)
at java.lang.Thread.run(Thread.java:748)
This is printed in the traceback when trying to generate the voxel mesh in some projects. This error seems seems to only occur in Java 1.8, which according to your build.gradle, you support. I'd be happy to provide more information to help you fix this.
The water block is now a CUBE, where the y-coordinate is lowered in the shader.
Now there is the configurable Slab shape, this should be used instead of the lowered cube shape.
At least, this is what I think is happening.
I'm adding a custom shape registry in simpleInitApp()
after I initialize the blocks config:
BlocksConfig.initialize(assetManager);
BlocksConfig.getInstance().setChunkSize(new Vec3i(Chunk.WIDTH, Chunk.HEIGHT, Chunk.LENGTH));
meshRegistry = new MeshRegistry();
BlocksConfig.getInstance().setShapeRegistry(meshRegistry);
All that MeshRegistry
does is override the get()
method to patch into my custom system, which is tested to work:
@Override
public Shape get(String name) {
System.out.println("Pulling from custom shape registry");
try {
return loadMesh(name);
} catch (IOException e) {
System.out.println("Cannot load mesh file "+name+". Falling back to JME Blocks shape registry.");
return super.get(name);
}
}
Yet, when I try to compile the chunk mesh, I get a NullPointerException
tracing back to com.rvandoosselaer.blocks.FacesMeshGenerator.createNode(FacesMeshGenerator.java:59)
, which looking into the source code reveals to be:
// add the block mesh to the chunk mesh
Shape shape = shapeRegistry.get(block.getShape());
shape.add(blockLocation, chunk, mesh); <
What's interesting is that it's obviously calling shapeRegistry.get()
and getting back null
, but my test print statement, System.out.println("Pulling from custom shape registry");
, is not firing. This leads me to conclude that the shapeRegistry
variable inside FacesMeshGenerator
is not getting updated when I call BlocksConfig.setShapeRegistry()
, and the program is attempting to use a key belonging to my custom system on the default system, which would obviously return null
.
The full source code the project in which the issue was found is at http://scaffoldeditor.org under the editor_rendering
branch. Here's the full traceback. I'm running the whole JME program inside a Swing window, so it's rather long:
Compiling world...
Loading render world...
java.lang.NullPointerException
at com.rvandoosselaer.blocks.FacesMeshGenerator.createNode(FacesMeshGenerator.java:59)
at com.rvandoosselaer.blocks.Chunk.createNode(Chunk.java:163)
at org.scaffoldeditor.editor.editor3d.test.Tester.test(Tester.java:43)
at org.scaffoldeditor.editor.editor3d.EditorApp.runTestCode(EditorApp.java:190)
at org.scaffoldeditor.editor.ui.EditorWindow.runTestCode(EditorWindow.java:442)
at org.scaffoldeditor.editor.ui.EditorWindow$10.actionPerformed(EditorWindow.java:254)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.AbstractButton.doClick(AbstractButton.java:376)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:842)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:886)
at java.awt.Component.processMouseEvent(Component.java:6539)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6304)
at java.awt.Container.processEvent(Container.java:2239)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
at java.awt.Container.dispatchEventImpl(Container.java:2283)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
at java.awt.EventQueue$4.run(EventQueue.java:733)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
AL lib: (EE) alc_cleanup: 1 device not closed
Thank you for coming to my TED talk.
Register the default blocks. See #41
When placing a block in a chunk that is different then all the current blocks in that chunk, all the blocks in that chunk will become the block that you placed.
Note:
I am placing blocks using this code:
Block myBlock = blockRegistry.get(BlockIds.GRASS);
myBlock.setShape(ShapeIds.POLE);
chunkManager.addBlock(blockLocation.subtract(0.5f, 0.5f, 0.5f), myBlock)
I am using blocks version: 1.6.3
and minie version: 3.0.0+debug
Hello,
Would it be possible to add micro-blocks, where a single block is made of other smaller blocks?
Thanks,
Trevor
Add reflection option to fluids.
The queue's of the chunkmanager now work on a first come first serve principle. This behaviour can be adapted to use PriorityQueue's instead.
When no comparator is specified, the behaviour of the queue's will remain the same.
See this post for more information.
Adding blocks can become very verbose when doing this in code.
Describing blocks in a file is easier and doesn’t require code changes to add or remove blocks.
Extend BlockRegistry to register blocks from a file.
Next to loading blocks from a file a BlockFactory might also help. Some blocks come in multiple variants (shape facing in different directions) but have the same parameters. All those different variants could be generated and registered.
Hi there,
I am trying to use this library in my project and all works fine on my Mac, but as soon as I try to run it on windows I get an com.jme3.asset.AssetNotFoundException
exception(both with the version I build on windows and the one I build on my mac). Trying to build Blocks with gradle also fails, here is the log:
gradle build
> Task :test FAILED
com.rvandoosselaer.blocks.BlocksConfigTest > initializationError FAILED
com.jme3.asset.AssetNotFoundException at BlocksConfigTest.java:16
com.rvandoosselaer.blocks.BlocksManagerTest > initializationError FAILED
com.jme3.asset.AssetNotFoundException at BlocksManagerTest.java:17
com.rvandoosselaer.blocks.ChunkTest > initializationError FAILED
com.jme3.asset.AssetNotFoundException at ChunkTest.java:14
com.rvandoosselaer.blocks.FacesMeshGeneratorTest > initializationError FAILED
com.jme3.asset.AssetNotFoundException at FacesMeshGeneratorTest.java:23
com.rvandoosselaer.blocks.FileRepositoryTest > initializationError FAILED
com.jme3.asset.AssetNotFoundException at FileRepositoryTest.java:23
14 tests completed, 5 failed
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///C:/Users/?/Desktop/Blocks-1.1.0/build/reports/tests/test/index.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 10s
5 actionable tasks: 5 executed
Thanks for this awesome project nonetheless dude :)
Update the AppSettings object on the examples. By default they should all:
Useful in editors.
public boolean remove(Block block) {
return remove(block.getName());
}
public boolean remove(String name) {
if(registry.containsKey(name)) {
Block remove = registry.remove(name);
if (log.isTraceEnabled()) {
log.trace("Removed block {} -> {}", name, remove);
}
return true;
}
return false;
}
Hi, after my first issue and your really fast help I would like to raise another issue.
If I create a plane of blocks (100x100) and walk over it my y position changes ever so slightly while I move, creating very weird effects, is it me, or are the blocks not perfectly level? We are talking 0.01-0.02 Δy.
Adding to this, there is also a very visible cut between blocks one one axis (I think its along the x axis)
Thanks for your help again :)
The Material and shader files should be cleaned up. Since the introduction of the new Fluid-pbr
material, the legacy Water
and Water-pbr
materials are deprecated.
The new Fluid-pbr
material uses texture scrolling instead of the spritesheet aproach of the legacy Water
and Water-pbr
materials.
The default-block
material should be updated to extend from PBRLighting.j3md instead of Lighting.j3md.
Edit: instead of removing all water related material definitions, create a new Fluid material definition with the texture scrolling properties. The default theme of blocks will still be based on the Phong Lighting material.
When using the ChunkPager it happened once that a Chunk was evicted from the ChunkCache while the ChunkManager was still generating the mesh.
This resulted in a NPE in the Chunk class:
public Block getBlock(int x, int y, int z) {
if (isInsideChunk(x, y, z)) {
return this.blocks[calculateIndex(x, y, z)];
}
...
the this.blocks
variable is null
when the chunk is cleaned up.
This doesn't break the functionality since the ChunkPager decided that the chunk should not be rendered (hence the evict). But there is probably a better way to handle this behaviour. All tasks for chunks that are discarded should be aborted.
The center point of a block shape is now at (0.5, 0, 0.5). This was intended so that the y-value of a block is equal to it's height in the world and to easily rotate around the y-axis.
When adding more and more blocks and shapes to Blocks it becomes clear that a lot of blocks require an inverted shape (rotated around z or x axis). Since the center point is at the bottom of a block, this inverted shape cannot be obtained from rotating the mesh of the non-inverted shape.
By changing the center point to (0.5, 0.5, 0.5) one shape can be rotated in 6 directions without the need of additional shapes.
All existing shape's should be adapted and cleaned up.
There are no tests written to confirm the behaviour of the registries.
It would be good to be able to toggle a 'debug grid' in Blocks. Showing the edges of a chunk as a wirebox.
It will be nice to add an API that can work with both GSON or Jackson. So those already using GSON won't need to also add Jackson.
Thanks
It's already possible to request a chunk from the chunkmanager when it's not available. But there is no way of manually passing a chunk to the chunkmanager.
This can be usefull if you have a chunk and want to give it to the chunkmanager to further take care of it.
Hello, I was having trouble using the getChunk method, so could someone explain how to use it properly ? Thanks
Add the ability to color (parts of) the textures of a block. By supplying an optional color-key map and a color.
This way you can dynamically change the color of a block:
TypeRegistry typeRegistry = BlocksConfig.getInstance().getTypeRegistry();
Material grassMaterial = typeRegistry.get(TypeIds.GRASS);
grassMaterial.setColor("KeyColor", ColorRGBA.Blue);
Separate these blend functions in a glsllib file.
functions:
see: https://en.wikipedia.org/wiki/Blend_modes#Multiply_and_Screen
Update FluidDepth filter, add flag to switch between blend modes. (overlay/layer)
Submitting this here so that won't be lost on the forum ;)
As suggested in the forum, this will be nice to add a similar foam effect that randomly generates foam on water surface.
@rvandoosselaer can this be done in the FluidFilter?
All of the normals in a face of the chunk mesh are facing in the same direction.
This means that doing per vertex lighting should almost have the same results as the default per pixel lighting but will be a lot faster.
Enable vertex lighting in the material and check the results.
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.