Git Product home page Git Product logo

jmccc's Introduction

JMCCC

Maven Central Gitter

A powerful open-source library for launching and downloading Minecraft.

License

JMCCC is licensed under the MIT license.

Features

  • Launches all versions of Minecraft
  • Scalable authentication
    • Supports Microsoft Account/Mojang Account/Offline, and can be extended
  • Downloads all versions of Minecraft
    • Supports Forge/Liteloader/Fabric/Quilt
      • Supports Liteloader snapshots
      • Supports Fabric/Quilt in Minecraft snapshots
    • Customizable download source
    • Asynchronous task system
    • Supports BIO/NIO
    • Supports caching
      • Can work on top of Ehcache or javax.cache
      • Different strategies for different files
  • Mojang API supports
    • Game profiles lookup
    • Fetches/Uploads textures
    • Fetches account information
    • Fetches name history
    • Blocked servers checking

Quick Start

Dependencies

Dependency Description
dev.3-3:jmccc Minecraft launching feature.
dev.3-3:jmccc-mcdownloader Minecraft downloading feature.
dev.3-3:jmccc-microsoft-authenticator Microsoft Account authentication feature.
dev.3-3:jmccc-mojang-api Mojang API client.
dev.3-3:jmccc-yggdrasil-authenticator Mojang Account authentication feature.

JMCCC RELEASE version has been uploaded to MAVEN CENTRAL:

https://repo1.maven.org/maven2/

If you do need the snapshot repository:

https://s01.oss.sonatype.org/content/repositories/snapshots/

Launching Minecraft

MinecraftDirectory dir = new MinecraftDirectory("/home/user/.minecraft");
Launcher launcher = LauncherBuilder.buildDefault();
launcher.launch(new LaunchOption("1.19.3", MicrosoftAuthenticator.login(it -> System.out.println(it.message)), dir));

You can use Microsoft Account with MicrosoftAuthenticator.login(it -> System.out.println(it.message)), also you can use YggdrasilAuthenticator.password("<email>", "<password>") with Mojang Account or new OfflineAuthenticator("<username>") if you want to use offline authentication.

Downloading Minecraft

MinecraftDirectory dir = new MinecraftDirectory("/home/user/.minecraft");
MinecraftDownloader downloader = MinecraftDownloaderBuilder.buildDefault();
downloader.downloadIncrementally(dir, "1.19.3", new CallbackAdapter<Version>() {
	
	@Override
	public void failed(Throwable e) {
		// when the task fails
	}
	
	@Override
	public void done(Version result) {
		// when the task finishes
	}
	
	@Override
	public void cancelled() {
		// when the task cancels
	}
	
	@Override
	public <R> DownloadCallback<R> taskStart(DownloadTask<R> task) {
		// when a new sub download task starts
		// return a DownloadCallback to listen the status of the task
		return new CallbackAdapter<R>() {

			@Override
			public void done(R result) {
				// when the sub download task finishes
			}

			@Override
			public void failed(Throwable e) {
				// when the sub download task fails
			}

			@Override
			public void cancelled() {
				// when the sub download task cancels
			}

			@Override
			public void updateProgress(long done, long total) {
				// when the progress of the sub download task has updated
			}

			@Override
			public void retry(Throwable e, int current, int max) {
				// when the sub download task fails, and the downloader decides to retry the task
				// in this case, failed() won't be called
			}
		};
	}
});

You can pass a null callback if you don't want to monitor the whole task. You can also return null in taskStart() if you don't want to monitor sub tasks.

Don't forget to shutdown the downloader when you are no longer going to use it.

downloader.shutdown();

Downloading Forge/Liteloader/Fabric/Quilt

MinecraftDirectory dir = new MinecraftDirectory("/home/user/.minecraft");
ForgeDownloadProvider forgeProvider = new ForgeDownloadProvider();
LiteloaderDownloadProvider liteloaderProvider = new LiteloaderDownloadProvider();
MinecraftDownloader downloader = MinecraftDownloaderBuilder.create()
	.providerChain(DownloadProviderChain.create()
		.addProvider(forgeProvider)
		.addProvider(liteloaderProvider))
	.build();

downloader.downloadIncrementally(dir, "1.19.3-forge-44.1.7", new CallbackAdapter<Version>() {...});
downloader.downloadIncrementally(dir, "1.12.2-LiteLoader1.12.2", new CallbackAdapter<Version>() {...});
downloader.downloadIncrementally(dir, "fabric-loader-0.14.13-1.19.3", new CallbackAdapter<Version>() {...});
downloader.downloadIncrementally(dir, "quilt-loader-0.17.11-1.19.3", new CallbackAdapter<Version>() {...});
downloader.download(forgeProvider.forgeVersionList(), new CallbackAdapter<ForgeVersionList>() {...});
downloader.download(liteloaderProvider.liteloaderVersionList(), new CallbackAdapter<LiteloaderVersionList>() {...});

FML options

JMCCC won't add fml options (such as -Dfml.ignoreInvalidMinecraftCertificates=true and -Dfml.ignorePatchDiscrepancies=true) to the command line automatically. If you have problems launching forge, you may need to add these arguments manually. These arguments are already defined in class ExtraArgumentsTemplates.

option.extraJvmArguments().add(ExtraArgumentsTemplates.FML_IGNORE_INVALID_MINECRAFT_CERTIFICATES);
option.extraJvmArguments().add(ExtraArgumentsTemplates.FML_IGNORE_PATCH_DISCREPANCISE);

jmccc's People

Contributors

xfl03 avatar yushijinhun avatar zhoulifu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jmccc's Issues

在setServerInfo()后, 当服务器无法连接上时, 客户端变为白屏

log节选

[21:01:17] [Client thread/INFO]: Connecting to m*******.****.cc, 25565 (已打码)
[21:01:17] [Client thread/INFO]: Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:LunatriusCore, FMLFileResourcePack:Dynamic Lights, FMLFileResourcePack:Dynamic Lights Burning Entity Module, FMLFileResourcePack:Dynamic Lights Creeper Module, FMLFileResourcePack:Dynamic Lights EntityItem Module, FMLFileResourcePack:Dynamic Lights Entity Light Module, FMLFileResourcePack:Dynamic Lights Mob Equipment Light Module, FMLFileResourcePack:Dynamic Lights Fiery Arrows Light Module, FMLFileResourcePack:Dynamic Lights Flood Light, FMLFileResourcePack:Dynamic Lights OtherPlayers Light Module, FMLFileResourcePack:Dynamic Lights Player Light Module, FMLFileResourcePack:Waila, FMLFileResourcePack:InGame Info XML, FMLFileResourcePack:Inventory Tweaks, FMLFileResourcePack:Just Enough Items, FMLFileResourcePack:Waila Harvestability, FMLFileResourcePack:Mineshot, FMLFileResourcePack:Mouse Tweaks, LiteLoader, VoxelMap, Mouse Tweaks
[OptiFine] *** Reloading textures ***
[OptiFine] Resource packs: Default
[OptiFine] Mipmap levels: 4
[OptiFine] Multitexture: false
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/0_glass_white/glass_pane_white.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/0_glass_white/glass_white.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/10_glass_purple/glass_pane_purple.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/10_glass_purple/glass_purple.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/11_glass_blue/glass_blue.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/11_glass_blue/glass_pane_blue.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/12_glass_brown/glass_brown.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/12_glass_brown/glass_pane_brown.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/13_glass_green/glass_green.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/13_glass_green/glass_pane_green.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/14_glass_red/glass_pane_red.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/14_glass_red/glass_red.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/15_glass_black/glass_black.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/15_glass_black/glass_pane_black.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/1_glass_orange/glass_orange.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/1_glass_orange/glass_pane_orange.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/2_glass_magenta/glass_magenta.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/2_glass_magenta/glass_pane_magenta.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/3_glass_light_blue/glass_light_blue.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/3_glass_light_blue/glass_pane_light_blue.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/4_glass_yellow/glass_pane_yellow.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/4_glass_yellow/glass_yellow.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/5_glass_lime/glass_lime.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/5_glass_lime/glass_pane_lime.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/6_glass_pink/glass_pane_pink.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/6_glass_pink/glass_pink.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/7_glass_gray/glass_gray.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/7_glass_gray/glass_pane_gray.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/8_glass_silver/glass_pane_silver.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/8_glass_silver/glass_silver.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/9_glass_cyan/glass_cyan.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/9_glass_cyan/glass_pane_cyan.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/bookshelf.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/glass.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/glasspane.properties
[OptiFine] ConnectedTextures: mcpatcher/ctm/default/sandstone.properties
[OptiFine] Multipass connected textures: false
[OptiFine] Custom loader: TextureAtlasSprite{name='minecraft:white', frameCount=1, rotated=false, x=688, y=480, height=16, width=16, u0=0.6718848, u1=0.6874902, v0=0.93751955, v1=0.96873045}
[21:01:23] [Client thread/INFO]: Created: 1024x512 textures-atlas
[21:01:24] [Client thread/INFO]: Calling late init for mod VoxelMap
[21:01:24] [Client thread/WARN]: =============================================================
[21:01:24] [Client thread/WARN]: MOD HAS DIRECT REFERENCE System.exit() THIS IS NOT ALLOWED REROUTING TO FML!
[21:01:24] [Client thread/WARN]: Offendor: com/thevoxelbox/voxelmap/c/h.if()V
[21:01:24] [Client thread/WARN]: Use FMLCommonHandler.exitJava instead
[21:01:24] [Client thread/WARN]: =============================================================
[21:01:24] [Client thread/WARN]: =============================================================
[21:01:24] [Client thread/WARN]: MOD HAS DIRECT REFERENCE System.exit() THIS IS NOT ALLOWED REROUTING TO FML!
[21:01:24] [Client thread/WARN]: Offendor: com/thevoxelbox/voxelmap/c/h.for()V
[21:01:24] [Client thread/WARN]: Use FMLCommonHandler.exitJava instead
[21:01:24] [Client thread/WARN]: =============================================================
[21:01:25] [Client thread/INFO]: Created: 256x128 waypoints-atlas
[21:01:25] [Client thread/INFO]: Created: 128x128 chooser-atlas
[21:01:25] [Client thread/INFO]: Created: 512x256 mobs-atlas
[21:01:25] [Client thread/INFO]: Baking listener list for ViewportListener with 0 listeners
[21:01:25] [Client thread/INFO]: Sound handler reload inhibit removed
[21:01:25] [Client thread/INFO]: Reloading sound handler
[21:01:25] [Client thread/INFO]: SoundSystem shutting down...
[21:01:26] [Client thread/WARN]: Author: Paul Lamb, www.paulscode.com
[21:01:26] [Sound Library Loader/INFO]: Starting up SoundSystem...
[21:01:26] [Thread-17/INFO]: Initializing LWJGL OpenAL
[21:01:26] [Thread-17/INFO]: (The LWJGL binding of OpenAL.  For more information, see http://www.lwjgl.org)
[21:01:26] [Thread-17/INFO]: OpenAL initialized.
[21:01:26] [Sound Library Loader/INFO]: Sound engine started
[21:01:27] [Client thread/INFO]: Baking listener list for GameLoopListener with 0 listeners
[21:01:27] [Client thread/INFO]: Baking listener list for RenderListener with 1 listeners
[OptiFine] *** Reloading custom textures ***
[OptiFine] Enable face culling: acacia_leaves, birch_leaves, dark_oak_leaves, jungle_leaves, oak_leaves, spruce_leaves
[21:01:27] [Client thread/INFO]: Baking listener list for TickObserver with 3 listeners
[21:01:27] [Client thread/INFO]: Baking listener list for PostRenderObserver with 3 listeners
[21:01:27] [Client thread/INFO]: Baking listener list for Tickable with 1 listeners
[21:01:27] [Client thread/INFO]: Baking listener list for FrameBufferListener with 0 listeners
[21:01:38] [Server Connector #1/ERROR]: Couldn't connect to server

客户端:

启动时:
启动时

启动完成后, 并且出现ServerConnector#ERROR: (已经是检测到无法连接至服务器, 但客户端是白屏)
启动完成后, 并且出现ServerConnector#ERROR

在原版(无forge)的时候不会出现此情况

1.7.2版本资源文件问题

继上回 Issues #8 的延伸

主要问题

虽然在 #8 内对于1.7.2及以下版本无法直接启动的问题已经解决,但是近日本人测试的时候发现系统并没有自动生成“虚拟”文件夹(assets/virtual/)并使用,结果发生了一系列搞怪的问题:

已设置简体中文语言,但依旧显示英文

已设置简体中文语言,但依旧显示英文

indexes文件正常

indexes文件正常

语言文件也没有任何损坏

语言文件也没有任何损坏

解决方案

个人设想的解决方案是:像正版启动器那样工作,读取indexes文件,然后将那些以hash值为文件名的文件重命名为原来的文件名,然后统一放到virtual/legacy文件夹里,接着让Minecraft读取使用。

十分抱歉为开发人员添加工作量,但十分希望能尽快解决!
thx

Can't launch 1.7.10 forge?

Hi, when attempting to launch 1.7.10 forge (1.7.10-forge1.7.10-10.13.0.1180), but when launching any version > 1.7.10 like 1.8 the program launches perfectly. Nothing different in the console, it just simply won't launch 1.7.10

jmccc 3.0

  • 将version升至3.0-SNAPSHOT
  • 将java版本切换为java8
  • 完全重写
    • 语言为kotlin

...其它项目还在考虑中

Forge url parsing error [1.6.1-forge1.6.1-8.9.0.775]

Integration test: jmccc-integration-test #18 [to2mbn Jenkins]

Console output:

====================
Testing 1.6.1-forge1.6.1-8.9.0.775
* Downloaded: http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.6.1-8.9.0.775/forge-1.6.1-8.9.0.775-installer.jar
* Downloaded: https://libraries.minecraft.net/net/minecraft/launchwrapper/1.3/launchwrapper-1.3.jar
* Retry (1/3): http://s3.amazonaws.com/Minecraft.Download/versions/Forge8.9.0.775/Forge8.9.0.775.jar
java.io.IOException: Illegal http response code: 403
    at org.to2mbn.jmccc.mcdownloader.download.io.async.HttpAsyncDownloader$DownloadSessionHandler$DataConsumer.onResponseReceived(HttpAsyncDownloader.java:69)
    at org.apache.http.nio.protocol.AbstractAsyncResponseConsumer.responseReceived(AbstractAsyncResponseConsumer.java:127)
    at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:315)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:302)
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:257)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
    at java.lang.Thread.run(Thread.java:745)
* Retry (2/3): http://s3.amazonaws.com/Minecraft.Download/versions/Forge8.9.0.775/Forge8.9.0.775.jar
java.io.IOException: Illegal http response code: 403
    at org.to2mbn.jmccc.mcdownloader.download.io.async.HttpAsyncDownloader$DownloadSessionHandler$DataConsumer.onResponseReceived(HttpAsyncDownloader.java:69)
    at org.apache.http.nio.protocol.AbstractAsyncResponseConsumer.responseReceived(AbstractAsyncResponseConsumer.java:127)
    at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:315)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:302)
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:257)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
    at java.lang.Thread.run(Thread.java:745)
* Failed: http://s3.amazonaws.com/Minecraft.Download/versions/Forge8.9.0.775/Forge8.9.0.775.jar
java.io.IOException: Illegal http response code: 403
    at org.to2mbn.jmccc.mcdownloader.download.io.async.HttpAsyncDownloader$DownloadSessionHandler$DataConsumer.onResponseReceived(HttpAsyncDownloader.java:69)
    at org.apache.http.nio.protocol.AbstractAsyncResponseConsumer.responseReceived(AbstractAsyncResponseConsumer.java:127)
    at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:315)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:302)
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:257)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
    at java.lang.Thread.run(Thread.java:745)

Caught an exception:
org.to2mbn.jmccc.integration.TestFailureException: Test Failure: 1.6.1-forge1.6.1-8.9.0.775
    at org.to2mbn.jmccc.integration.LaunchHandler.testJmccc(LaunchHandler.java:240)
    at org.to2mbn.jmccc.integration.Main.main(Main.java:56)
Caused by: java.util.concurrent.ExecutionException: java.io.IOException: Illegal http response code: 403
    at org.to2mbn.jmccc.mcdownloader.download.concurrent.AsyncFuture.getResult(AsyncFuture.java:147)
    at org.to2mbn.jmccc.mcdownloader.download.concurrent.AsyncFuture.get(AsyncFuture.java:71)
    at org.to2mbn.jmccc.mcdownloader.download.concurrent.CallbackAsyncTask.get(CallbackAsyncTask.java:153)
    at org.to2mbn.jmccc.integration.LaunchHandler.testJmccc(LaunchHandler.java:194)
    ... 1 more
Caused by: java.io.IOException: Illegal http response code: 403
    at org.to2mbn.jmccc.mcdownloader.download.io.async.HttpAsyncDownloader$DownloadSessionHandler$DataConsumer.onResponseReceived(HttpAsyncDownloader.java:69)
    at org.apache.http.nio.protocol.AbstractAsyncResponseConsumer.responseReceived(AbstractAsyncResponseConsumer.java:127)
    at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:315)
    at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
    at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:302)
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:257)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:278)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:590)
    at java.lang.Thread.run(Thread.java:745)
====================

为什么验证的时候出错

错误信息如下:[2017-03-21 08:15:14,426] [WARN] [http-apr-8080-exec-4] [yushijinhun.authlibagent.web.yggdrasil.servlet.AuthenticateServlet] unexcept exception
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:132) ~[spring-orm-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687) ~[hibernate-core-5.1.0.Final.jar:5.1.0.Final]
at yushijinhun.authlibagent.service.LoginServiceImpl.loginWithPassword(LoginServiceImpl.java:46) ~[classes/:?]
at yushijinhun.authlibagent.service.LoginService.loginWithPassword(LoginService.java:22) ~[classes/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_121]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at com.sun.proxy.$Proxy60.loginWithPassword(Unknown Source) ~[?:?]
at yushijinhun.authlibagent.service.YggdrasilServiceImpl.authenticate(YggdrasilServiceImpl.java:57) ~[classes/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_121]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) ~[spring-aop-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at com.sun.proxy.$Proxy66.authenticate(Unknown Source) ~[?:?]
at yushijinhun.authlibagent.web.yggdrasil.servlet.AuthenticateServlet.process(AuthenticateServlet.java:19) ~[classes/:?]
at yushijinhun.authlibagent.web.yggdrasil.servlet.AuthenticateServlet.process(AuthenticateServlet.java:8) ~[classes/:?]
at yushijinhun.authlibagent.web.yggdrasil.servlet.YggdrasilPostServlet.process(YggdrasilPostServlet.java:37) ~[classes/:?]
at yushijinhun.authlibagent.web.yggdrasil.servlet.YggdrasilServlet.handleRequest(YggdrasilServlet.java:48) [classes/:?]
at yushijinhun.authlibagent.web.yggdrasil.servlet.YggdrasilPostServlet.doPost(YggdrasilPostServlet.java:21) [classes/:?]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) [servlet-api.jar:?]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [servlet-api.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) [catalina.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:?]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.0.42]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) [catalina.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:?]
at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151) [spring-orm-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) [catalina.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:?]
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) [log4j-web-2.5.jar:2.5]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) [catalina.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) [catalina.jar:?]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) [catalina.jar:?]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94) [catalina.jar:?]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [catalina.jar:?]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [catalina.jar:?]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:?]
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) [catalina.jar:?]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502) [catalina.jar:?]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1104) [tomcat-coyote.jar:8.0.42]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684) [tomcat-coyote.jar:8.0.42]
at org.apache.tomcat.util.net.AprEndpoint$SocketWithOptionsProcessor.run(AprEndpoint.java:2445) [tomcat-coyote.jar:8.0.42]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_121]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_121]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.42]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]

1.15.2Fabric-loader启动出问题

纯净版没有问题,Fabric启动会缺失资源文件,声音图标语言文件都没有。

[15:18:58] [main/ERROR]: Couldn't set icon
java.io.FileNotFoundException: icons/icon_16x16.png
at net.minecraft.class_3268.method_14405(class_3268.java:89) ~[intermediary-1.15.2.jar:?]
at net.minecraft.class_310.(class_310.java:420) [intermediary-1.15.2.jar:?]
at net.minecraft.client.main.Main.main(Main.java:166) [intermediary-1.15.2.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_201]
at net.fabricmc.loader.game.MinecraftGameProvider.launch(MinecraftGameProvider.java:193) [fabric-loader-0.7.8+build.185.jar:?]
at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:138) [fabric-loader-0.7.8+build.185.jar:?]
at net.fabricmc.loader.launch.knot.KnotClient.main(KnotClient.java:26) [fabric-loader-0.7.8+build.185.jar:?]
[15:19:00] [main/INFO]: Narrator library for x64 successfully loaded
[15:19:01] [main/INFO]: Reloading ResourceManager: Default, Fabric Renderer API (v1), Fabric Networking Block Entity (v0), Fabric Key Bindings (v0), VexView, Fabric Renderer - Indigo, Fabric Containers (v0), Fabric Biomes (v1), Fabric Crash Report Info (v1), Fabric Events Interaction (v0), Fabric API Base, Fabric Rendering (v0), Fabric Rendering (v1), Fabric Rendering Data Attachment (v1), Fabric Resource Loader (v0), Fabric Textures (v0), Fabric Content Registries (v0), Fabric Tag Extensions (v0), Fabric Rendering Fluids (v1), Fabric Commands (v0), Fabric Registry Sync (v0), Hwyla, Fabric BlockRenderLayer Registration (v1), Fabric Mining Levels (v0), Fabric Renderer Registries (v1), VoxelMap, Fabric Events Lifecycle (v0), Fabric Loot Tables (v1), Fabric API, Fabric Item Groups (v0), Fabric Models (v0), Fabric Object Builders (v0), Fabric Networking (v0)
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.cave
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.enter
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.exit
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.loop
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.loop.additions
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.loop.additions.rare
[15:19:14] [main/WARN]: Missing sound for event: minecraft:ambient.underwater.loop.additions.ultra_rare
[15:19:14] [main/WARN]: Missing sound for event: minecraft:block.anvil.break
.......

Run Local Versions like OPTIFINE MODS etc

There is no way to run local mods like optifine or similar, is there a way?
example error:
java.io.IOException: Couldn't parse version json: 1.19.2-Aristois
at org.to2mbn.jmccc.version.parsing.Versions.resolveVersion(Versions.java:44)
at org.to2mbn.jmccc.option.LaunchOption.requireVersion(LaunchOption.java:125)
at org.to2mbn.jmccc.option.LaunchOption.(LaunchOption.java:101)
at launcherabf.menu.ejecutarmc(menu.java:344)
at launcherabf.menu$2.actionPerformed(menu.java:103)

public static Version resolveVersion(MinecraftDirectory minecraftDir, String version) throws IOException {
Objects.requireNonNull(minecraftDir);
Objects.requireNonNull(version);

    if (doesVersionExist(minecraftDir, version)) {
        try {
            return getVersionParser().parseVersion(resolveVersionHierarchy(version, minecraftDir), PlatformDescription.current());
        } catch (JSONException e) {
            throw new IOException("Couldn't parse version json: " + version, e);
        }
    } else {
        return null;
    }
}

Can't download Forge or Liteloader

Error exception thrown at an attempt to download Forge (1.8-forge1.8-11.14.3.1514):
http://pastebin.com/fE5gfJm7
This does create a Forge folder in the versions folder.

Error exception thrown at an attempt to download Liteloader(1.8-LiteLoader1.8):
http://pastebin.com/uw87GqLY
This does not make a Liteloader folder and appears to happen during a sub download as it shows the retry message which is only printed if the downloading fails during a sub download.

This is most likely my own fault so please tell me what I'm doing wrong, thanks in advance.

无法启动安装了mcheli的1.7.10客户端

Jmccc调用代码与http://www.mcbbs.net/thread-573154-1-1.html中所示一致
Forge日志文件显示如下:
[时间] [Client thread/ERROR]: Found a duplicate mod mcheli at [路径.minecraft, 路径.minecraft\mods\mcheli]
之前有显示mcheli加载了两次,一次不能找到mcmod.info,第二次可以找到。
如果将mcheli放入mods下的1.7.10文件夹,forge会多识别出一个mcheli,并且依旧不能找到mcmod.info
其他启动器正常,MinecraftForum上有提到一款名为FTB Launcher的启动器存在同样的问题

我已经导入证书了 怎么还是这样?

[INFO] Scanning for projects...
[INFO] Downloading: https://maven.lazercloud.com/nexus/content/groups/public/org/sonatype/plugins/nexus-staging-maven-plugin/1.6.6/nexus-staging-maven-plugin-1.6.6.pom
[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[ERROR] Unresolveable build extension: Plugin org.sonatype.plugins:nexus-staging-maven-plugin:1.6.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.sonatype.plugins:nexus-staging-maven-plugin:jar:1.6.6 @
@
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]
[ERROR] The project org.to2mbn:jmccc-parent:3.0-SNAPSHOT (C:\Users\Anyways\Desktop\JMCCC\JMCCC\pom.xml) has 1 error
[ERROR] Unresolveable build extension: Plugin org.sonatype.plugins:nexus-staging-maven-plugin:1.6.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.sonatype.plugins:nexus-staging-maven-plugin:jar:1.6.6: Could not transfer artifact org.sonatype.plugins:nexus-staging-maven-plugin:pom:1.6.6 from/to maven-Lazercloud-cn (https://maven.lazercloud.com/nexus/content/groups/public/): sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target -> [Help 2]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
[ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/PluginManagerException

Problem with authentication

On line 65 of YggdrasilAuthenticator, it returns password(username, password, null), but throws a NullPointerException, and when I remove the null part, it doesn't throw any exceptions, but doesn't authenticate or launch the game.

Is this a bug, or am I doing something wrong? I just copy & pasted the example, and launching with an OfflineAuthenticator works fine, it get's stuck when I try to authenticate a real account.

EDIT: I know that this project might be discontinued, but I'm pretty sure Mojang hasn't made any major changes to their API since then, so that's why I thought I would just ask for help.

授权申请

你好,我是一个服务器的服主,我想要使用你们的jmccc api来完成启动器启动游戏的功能。由于MIT许可证的原因,我希望你们可以授权于我。先谢谢啦。

Change JMCCC's license

Recent days, we discovered that the Unlicense was too open. It allows everyone to use or modify the source code, which might cause some problems. So we finally decided to change the license of JMCCC to MIT license.

The old commits will be still under Unlicense. And the new ones will be under MIT License.

In order to change the license of JMCCC, we need contributors' agreements.
The following is the contributor list. (Strikethrough means we have already got the contributor's agreement.)

If you are in the list above, and you agree to change the license, please reply with something along the words of: "I permit the license of my contributions to JMCCC project to be changed to the MIT License."

lwjgl.dll过敏.

Jmccc似乎只支持Java8.
而且在32位Java环境下 似乎对
lwjgl.dll过敏.
.minecraft\natives\lwjgl.dll: %1 不是有效的 Win32 应用程序。
这样的提示 而其他启动器均能正确启动
就这些啦 希望给一个答复 大触

不支持1.7.2版本启动?

我在使用JMCCC的时候遇到了一些问题,希望能得到一些答复

事情是这样的:

本人最近(实际上是今天)写了个针对某服务器的启动器,本人也按照README里的示例去写了启动代码,但是在测试的时候出现了问题:

java.io.IOException: unable to resolve json
    at com.github.to2mbn.jmccc.version.Versions.resolveVersion(Versions.java:39)
    at biz.cirno.jdj.cirnocraft.launcher.form.MainWindow$5.actionPerformed(MainWindow.java:308)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6516)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6281)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4872)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4698)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4698)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:740)
    at java.awt.EventQueue.access$300(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:699)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:713)
    at java.awt.EventQueue$4.run(EventQueue.java:711)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:710)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Caused by: org.json.JSONException: JSONObject["assets"] not found.
    at org.json.JSONObject.get(JSONObject.java:473)
    at org.json.JSONObject.getString(JSONObject.java:654)
    at com.github.to2mbn.jmccc.version.VersionParser.parse(VersionParser.java:26)
    at com.github.to2mbn.jmccc.version.Versions.resolveVersion(Versions.java:37)
    ... 37 more

根据错误消息可以判断出错误是因为版本json文件里缺少“assets”这个值发生的

但是问题来了:本人所在的服务器的客户端版本为1.7.2,版本文件里并不存在assets这个值,本人也翻阅了部分相关源代码也没能发现有关于这方面的解决方案。

请问这样的问题能否修复,或者给出个解决方案?

(JMCCC版本为最新的2.3.1)

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.