Coder Social home page Coder Social logo

egametang / et Goto Github PK

View Code? Open in Web Editor NEW
8.3K 478.0 2.9K 156.24 MB

Unity3D Client And C# Server Framework

License: Other

C# 89.98% Emacs Lisp 0.03% Batchfile 0.20% C 2.90% C++ 0.45% CMake 6.27% Shell 0.15% Smalltalk 0.01% PowerShell 0.02%
c-sharp server game-engine actor unity unity3d game meta metaverse mmo

et's Issues

MongodbDriver大小写问题

库上Server/ThirdParty/下面有MongodbDriver和MongoDBDriver两个文件夹,如果git的配置是ignorecase=true那本地的服务器工程能正确跑起来,否则很多文件拉不下来

unity 2018.211f1 打开报错

C:/Users/84675/AppData/Local/Unity/cache/packages/packages.unity.com/[email protected]/Editor/Sources/Services/Upm/UpmBaseOperation.cs(33,34): error CS1061: Type UnityEditor.PackageManager.PackageInfo' does not contain a definition for author' and no extension method author' of type UnityEditor.PackageManager.PackageInfo' could be found. Are you missing an assembly reference?

请问Web端支持吗

我用WebGL打包斗地主demo运行起来后,报错
System.TypeLoadException: Cannot find Adaptor for:ETModel.AEvent
at ILRuntime.CLR.TypeSystem.ILType.InitializeBaseType () [0x00000] in <00000000000000000000000000000000>:0

ComponentWithId的Bug

qq 20180614154535
Bson反序列化会默认调用无参构造函数,这里会导致组件从数据库取出来后Id被InstanceId覆盖

切换到ILRuntime就报错Cannot find Adaptor for:Model.IEvent

最新版的代码,按照说明可以跑起来,但是设置了Script Define Symbols加上ILRuntime之后,再启动程序就会报错,请问是什么原因呢?

System.TypeLoadException: Cannot find Adaptor for:Model.IEvent
  at ILRuntime.CLR.TypeSystem.ILType.InitializeInterfaces () [0x000d7] in D:\ET-master\Unity\Assets\ThirdParty\ILRuntime\ILRuntime\CLR\TypeSystem\ILType.cs:397 
  at ILRuntime.CLR.TypeSystem.ILType.get_FirstCLRInterface () [0x0000d] in D:\ET-master\Unity\Assets\ThirdParty\ILRuntime\ILRuntime\CLR\TypeSystem\ILType.cs:142 
  at ILRuntime.Runtime.Intepreter.ILTypeInstance..ctor (ILRuntime.CLR.TypeSystem.ILType type, System.Boolean initializeCLRInstance) [0x000a5] in D:\ET-master\Unity\Assets\ThirdParty\ILRuntime\ILRuntime\Runtime\Intepreter\ILTypeInstance.cs:164 
  at ILRuntime.CLR.TypeSystem.ILType.Instantiate (System.Boolean callDefaultConstructor) [0x00003] in D:\ET-master\Unity\Assets\ThirdParty\ILRuntime\ILRuntime\CLR\TypeSystem\ILType.cs:924 
  at ILRuntime.Runtime.Enviorment.AppDomain.Instantiate (System.String type, System.Object[] args) [0x0003b] in D:\ET-master\Unity\Assets\ThirdParty\ILRuntime\ILRuntime\Runtime\Enviorment\AppDomain.cs:878 
  at Model.IEventILMethod..ctor (System.Type type, System.String methodName) [0x00025] in D:\ET-master\Unity\Assets\Scripts\Component\EventComponent.cs:62 
  at Model.EventComponent.Load () [0x0011d] in D:\ET-master\Unity\Assets\Scripts\Component\EventComponent.cs:160 
  at Model.EventComponentEvent.Load () [0x00007] in D:\ET-master\Unity\Assets\Scripts\Component\EventComponent.cs:114 
  at Model.ObjectEvents.Load () [0x0006c] in D:\ET-master\Unity\Assets\Scripts\Base\Object\ObjectEvents.cs:249 

TimerComponent在WaitAsync时可能会报异常导致无限写日志

2018-01-20 18:00:00.0128 AllServer 001 (ObjectEvents.cs:265) System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at Model.TimerComponent.Update() in E:\WesternMini2017\ETFramework\trunk\Unity\Assets\Scripts\Component\TimerComponent.cs:line 49
at Model.TimerComponentEvent.Update() in E:\WesternMini2017\ETFramework\trunk\Unity\Assets\Scripts\Component\TimerComponent.cs:line 19
at Model.ObjectEvents.Update() in E:\WesternMini2017\ETFramework\trunk\Server\Model\Base\Object\ObjectEvents.cs:line 265

master打包切换到webgl就报错

Assets\Model\Module\Pathfinding\Recast\Serialization\JsonSerializer.cs(787,26): error CS0103: The name 'AstarData' does not exist in the current context

Assets\Model\Module\Pathfinding\AstarPathfindingProject\Core\AstarData.cs(40,11): error CS0246: The type or namespace name 'GridGraph' could not be found (are you missing a using directive or an assembly reference?)

Assets\Model\Module\Pathfinding\AstarPathfindingProject\Core\AstarData.cs(43,11): error CS0246: The type or namespace name 'PointGraph' could not be found (are you missing a using directive or an assembly reference?)

Assets\Model\Module\Pathfinding\AstarPathfindingProject\Core\AstarData.cs(45,11): error CS0246: The type or namespace name 'NavMeshGraph' could not be found (are you missing a using directive or an assembly reference?)

Assets\Model\Module\Pathfinding\AstarPathfindingProject\Core\AstarData.cs(47,11): error CS0246: The type or namespace name 'LayerGridGraph' could not be found (are you missing a using directive or an assembly reference?)

几处关于编译配置兼容的问题

目前把环境配置到mac下面,发现有几个编译配置不兼容,

Server的几个项目
Server.App
Server.Hotfix
Server.Model
MongoDB.Bson
MongoDB.Driver
MongoDB.Driver.Core

vs2017 会把代码生成在obj目录下,配置的路径是bin下面,编译时不会创建bin路径,在windows下面能正常编译生成,mac会报错 找不到路径

能否把项目的路径修改过来,如下

工程文件 *.csproj

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
     <DefineConstants>TRACE;DEBUG;NETCOREAPP2_0;SERVER</DefineConstants>
 -    <OutputPath>bin\Debug\..\..\..\..\Bin\</OutputPath>
 +    <OutputPath>obj\Debug\..\..\..\..\Bin\</OutputPath>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
     <DefineConstants>TRACE;RELEASE;NETCOREAPP2_0;SERVER</DefineConstants>
 -    <OutputPath>bin\Release\..\..\..\..\Bin\</OutputPath>
+    <OutputPath>obj\Release\..\..\..\..\Bin\</OutputPath>
</PropertyGroup>

MongoDB 查询报错 Can't compile a NewExpression with a constructor declared on an abstract class

    [BsonIgnoreExtraElements]
    public sealed class AccountInfo : ComponentWithId
    {
        public string account { get; set; } = null;
        public string nick_name { get; set; } = null;
        public string password { get; set; } = null;
        public decimal balance { get; set; } = 0m;

        public override string ToString()
        {
            return $"account : {this.account}, nick_name : {this.nick_name}, password : {this.password}, balance : {this.balance}";
        }
    }

使用AccountInfo进行如下查询的时候,会报错:

        [Get("login")]
        public async ETTask<HttpResult> Login(string account, string password)
        {
            var db = Game.Scene.GetComponent<DBProxyComponent>();
            var info = await db.Query<AccountInfo>(s => s.account.Equals(account));

            return info.Count > 0? Ok("success", info[0]) : Error($"not find {account}");
        }

错误信息如下:

2019-05-07 03:03:15.7763 AllServer 0001 System.Exception: Rpc Error: ETModel.DBQueryJsonRequest ---> ETModel.RpcException: Error: 102001 Message: System.Exception: 查询数据库异常! AccountInfo { "account" : "abcd0001" } ---> System.InvalidOperationException: Can't compile a NewExpression with a constructor declared on an abstract class
   at System.Linq.Expressions.Compiler.LambdaCompiler.EmitNewExpression(Expression expr)
   at System.Linq.Expressions.Compiler.LambdaCompiler.EmitExpression(Expression node, CompilationFlags flags)
   at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody(CompilerScope parent, Boolean inlined, CompilationFlags flags)
   at System.Linq.Expressions.Compiler.LambdaCompiler.EmitLambdaBody()
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
   at System.Linq.Expressions.Expression`1.Compile(Boolean preferInterpretation)
   at System.Linq.Expressions.Expression`1.Compile()
   at MongoDB.Bson.Serialization.BsonClassMap.GetCreator() in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/BsonClassMap.cs:line 1264
   at MongoDB.Bson.Serialization.BsonClassMap.CreateInstance() in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/BsonClassMap.cs:line 446
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.DeserializeClass(BsonDeserializationContext context) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs:line 140
   at MongoDB.Bson.Serialization.BsonClassMapSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs:line 100
   at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs:line 49
   at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/CursorBatchDeserializationHelper.cs:line 59
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateCursorBatch(BsonDocument commandResult) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/FindCommandOperation.cs:line 483
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.CreateCursor(IChannelSourceHandle channelSource, BsonDocument commandResult) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/FindCommandOperation.cs:line 460
   at MongoDB.Driver.Core.Operations.FindCommandOperation`1.ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/FindCommandOperation.cs:line 525
   at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/FindOperation.cs:line 442
   at MongoDB.Driver.OperationExecutor.ExecuteReadOperationAsync[TResult](IReadBinding binding, IReadOperation`1 operation, CancellationToken cancellationToken) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver/OperationExecutor.cs:line 39
   at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperationAsync[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, CancellationToken cancellationToken) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver/MongoCollectionImpl.cs:line 1055
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken) in /home/kevin/rider-workspace/ET/Server/ThirdParty/MongoDBDriver/MongoDB.Driver/MongoCollectionImpl.cs:line 1135
   at ETModel.DBQueryJsonTask.Run() in /home/kevin/rider-workspace/ET/Server/Model/Module/DB/DBQueryJsonTask.cs:line 33

请问这个该如何解决?

NativeMethods.enet_host_create抛出异常

托管调试助手“PInvokeStackImbalance”在“E:\UnityProjects\Egametang\Bin\App.vshost.exe”中检测到问题。

其他信息: 对 PInvoke 函数“Base!Base.NativeMethods::enet_host_create”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。

试过在DllImport的时候,CallingConvention的属性改为CallingConvention.Cdecl,然后会有其他的异常。

麻烦说一下,是哪点的问题呢,下面是调用的代码

public UPoller(string hostName, ushort port)
		{
			try
			{
				this.USocketManager = new USocketManager();

				UAddress address = new UAddress(hostName, port);
				ENetAddress nativeAddress = address.Struct;
				this.host = NativeMethods.enet_host_create(ref nativeAddress,
						NativeMethods.ENET_PROTOCOL_MAXIMUM_PEER_ID, 0, 0, 0);

				if (this.host == IntPtr.Zero)
				{
					throw new Exception("Host creation call failed.");
				}

				NativeMethods.enet_host_compress_with_range_coder(this.host);
			}
			catch (Exception e)
			{
				throw new Exception($"UPoll construct error, address: {hostName}:{port}", e);
			}
		}

4.x的版本号建议

4.x开始的版本号建议发release,这样在github上能更方便的看到稳定版本和更新情况, lts的话,后续发版本可以用4.x.x的版本号, 中间表示功能增加, 末位表示bug修复

发送内容为空的消息时接收方会报异常

image

当创建不包含额外内容的消息结构体,比如:
message C2M_ErrMessageTest // IActorLocationMessage
{
int32 RpcId = 90;
int64 ActorId = 93;
int64 Id = 94;
}
由客户端或服务器发送后,接收方会在 this.packetSize < 3 这里报错; 实际packetSize 为2,当将3修改为1时,可正常运行。

想问下,这里加的阈值的意义是什么?如何修改来兼容空内容的消息。

组件设计.md里“接口逻辑难以复用”这种说法是错误的

  1. 接口逻辑复用只要通过抽象类来共享逻辑就可以了。

  2. 觉得“难以热插拔”这样的说法也是有问题的。都抽象出接口了,当然可以在运行时进行热插拔。像文档里描述的骑马的情况,Player这个类是可骑行的,从描述上就是合理的,也不需要在运行时删除对这个接口的继承啊,一点逻辑代码而已,正常来说都不会携带额外数据。用接口究其原因还是为了解除耦合,隔离变化。你可以继承接口,当然也可以通过has a的关系将接口作为一个类的字段,都没问题,到头来还是看能不能活用。

Questions about server side scripting

Hello there,
I have taken an interest in some of these C++ distributed entity frameworks I have seen here on github and had a question about the scripting backend. I use Unity3d for my game and currently my client and server side are separated but it is all written in C#. It is setup as authoritative so the client only sends requests to the server and then the server processes these requests and sends the result back to the clients for everything from movement, spellcasting, inventory, etc. I also use several 3rd party server-side assets which of course need to run on the server side, but are all also written in C#. Would I be able to use something like ET if all of my current server code is C#, or would everything have to be rewritten? I looked into KBEngine before, but you can only use python for the server side and I definitely do not want to have to rewrite everything I already have, so I am trying to find something that might work for my particular case.

Thanks!
MostHated

调用FUI.Get会更改FairyGUI的子节点顺序,影响点击事件

FUI.Get 在获取子GObject的时候,如果没有子FUI,在调用FUI.Add(FUI ui)时会调用gComponent.AddChild重新添加该子节点,FairyGUI检测到该节点存在,调用SetChildIndex改变该节点顺序,导致点击事件层级和FairyGUI编辑器中的不一致。

C#

你好,我现在在看cmake protobuf,你这个是在windows还是linux?我目前在linux工作,所以想学学你的代码,看到有C# ?

创建行为树节点报错

NullReferenceException: Object reference not set to an instance of an object
MyEditor.BehaviorDesignerWindow.ShowSubWin (Vector2 pos, SubWinType subWinType) (at Assets/Editor/BehaviorTreeEditor/BehaviorDesignerWindow.cs:60)
MyEditor.GraphDesigner.PopUpCreate () (at Assets/Editor/BehaviorTreeEditor/GraphDesigner.cs:447)
UnityEditor.GenericMenu.CatchMenu (System.Object userData, System.String[] options, Int32 selected) (at C:/buildslave/unity/build/artifacts/generated/common/editor/GenericMenuBindings.gen.cs:124)

Unity.Editor.asmdef

自定义程序集Unity.Editor.asmdef可以不使用默认名称么(Unity.Editor)?这样第三方插件的editor就不会冲突了。

请问:使用Protobuf序列化数据爆出一下面的错误

2017-11-29 16:48:14.9084 AllServer 001 (Session.cs:109) message deserialize error, ip: 127.0.0.1:57087 119 ProtoBuf.ProtoException: No parameterless constructor found for Model.ARequest
at ProtoBuf.Meta.TypeModel.ThrowCannotCreateInstance(Type type) in C:\code\protobuf-net\src\protobuf-net\Meta\TypeModel.cs:line 1462
at proto_10(Object , ProtoReader )
at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, Object value, Boolean noAutoCreate)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context)
at ProtoBuf.Serializer.NonGeneric.Deserialize(Type type, Stream source)
at Model.ProtobufHelper.FromBytes(Type type, Byte[] bytes, Int32 index, Int32 length)
at Model.ProtobufPacker.DeserializeFrom(Type type, Byte[] bytes, Int32 index, Int32 count)
at Model.Session.RunDecompressedBytes(UInt16 opcode, Byte[] messageBytes, Int32 offset) Program.Main => OneThreadSynchronizationContext.Update => <>c__DisplayClass3_0.b__0 => ExecutionContext.Run => d__15.MoveNext => TaskCompletionSource1.SetResult => TaskCompletionSource1.TrySetResult => Task`1.TrySetResult => Task.RunContinuations => AwaitTaskContinuation.RunCallback => ExecutionContext.Run => d__13.MoveNext => Session.Run => Session.RunDecompressedBytes => Log.Error => NLogAdapter.Error

客户端UI组件 建议.

感觉UIComponent 放到 Model 这边的是不是比较合适一点,. 不在Hotfix那, 毕竟是大部分游戏都通用的模块.

建议与DOTS进行结合

Unity最新的DOTS带来了几个优势:1、ECS结构 2、Burst编译方式 3、与Job System 更好的结合,所以建议ET的Component和System结构可以与DOTS的ECS结合,这更便于ET的推广和发展

Memory Leak 内存泄漏

调用500次 ComponentFactory.Create()
所产生的物件调用dispose后,会产生内存泄漏
全部积在 Microsoft.IO.RecyclableMemoryStream

Concurrency/Parallelism related question

Hello!

I read (almost) all of ET code (and it is awesome) but I didn't saw any parallelism mechanism (threads, workers, etc), only concurrency ones (co-routines) and consequently no lock/semaphore objects. So I'm wondering how does it scales when there is a huge demand of messages to parse, by having a lot of players. One can accomplish it by having many distributed servers, each one with a "single" thread, but using co-routines?

Or there are something that I didn't saw?

新版本Unity中重新引用UnityEngine后Hotfix仍然报错

系统环境:
Windows 10 专业版 64位
Unity 2017.3.0f3
Visual Studio Community 2017 15.5.3

Hotfix中重新引用C:\Program Files\Unity2017\Editor\Data\Managed\UnityEngine\UnityEngine.dll后,会报错找不到GameObject和Object:

错误 CS0246 未能找到类型或命名空间名“GameObject”(是否缺少 using 指令或程序集引用?) Unity.Hotfix D:\Projects\Com\ET\Unity\Hotfix\UI\UILobby\Factory\UILobbyFactory.cs

改成引用C:\Program Files\Unity2017\Editor\Data\Managed\UnityEngine.dll后,会报错:

错误 CS0012 类型“MonoBehaviour”在未引用的程序集中定义。必须添加对程序集“UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”的引用。 Unity.Hotfix D:\Projects\Com\ET\Unity\Hotfix\UI\UILobby\Component\UILobbyComponent.cs

请问这是什么原因?

Dictionary 角标越界异常

List<AccountInfo> accountInfos = await proxyComponent.QueryJson<AccountInfo>($"{{Third_Id:'{message.Third_Id}'}}");
查询数据库的时候,报错
default

适配Android ARM64

请问可以适配一下arm64-v8a吗,好像主要是kcp的库要做一下适配,但是我拿到kcp的源码https://github.com/skywind3000/kcp
编译出的arm64的so库使用起来有问题,在发起请求C2R_Login的时候,服务端收到请求并reply()了,但是客户端却卡在这个请求里了,除非我退出游戏,代码才会继续往下执行(因为打出了日志)

(MacOS下)命令行工具,启动server,提示错误

server已经用visual studio for mac编译成功。

Win32Exception: ApplicationName='dotnet', CommandLine='App.dll --appId=1 --appType=Manager --config=../Config/StartConfig/127.0.0.1.txt', CurrentDirectory='../Bin/', Native error= Cannot find the specified file

关于玩家数据设计

如果玩家上线时从数据库拿出玩家的数据,假设名称为 PlayerEntity, 这个结构包含了玩家的各种数据,后面如果每次修改了以后都SaveDB一下,因为是整个PlayerEntity全部写入数据库,这样会不会导致数据库压力比较大,或者说专门开个Db服,玩家上线从Monogo拉取数据,玩家下线数据落地,这样的逻辑会好些吗? 求解答,也欢迎大家提出自己的方案和想法

Questions.

Yo, I have some questions about this project. It's missing readme in english, so it is difficult to know exactly what the server works, what are its features and usefulness.

  • Does the server support an MMORPG (more than 500 players)?
  • Server independent from client and unity?
  • How to works navmesh on server?

Cheers!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.