如何在客户端服务器PlayN游戏中处理RPC?

9
我想使用PlayN创建客户端/服务器纸牌游戏,例如Hearts。虽然我主要关注HTML5输出,但我最好是平台无关的输出,以防将来决定制作Android客户端。我该如何处理RPC机制?
以下是我考虑过的选项:
1. 使用get()/post()方法的JSON进行RPC - 编写接受/返回JSON的servlet,并使所有版本的客户端代码都使用它。这似乎可行,但我担心JSON的冗长性。一旦我让Hearts工作正常后,我想继续开发更复杂的游戏,而且我担心JSON会导致在客户端和服务器之间传递大量比必要更大的消息。我实际上不知道如何在Java中使用JSON,但我认为这是可以做到的。我的假设是否正确?Java与JSON的兼容性如何?
2. 继续使用GWT-RPC。我可以通过在我的核心(平台无关)构造函数中使用异步服务接口,在我的HTML main()中传入由GWT.create(MyService.class)生成的GWT Async接口(或至少是其包装器)。然而,我不知道这对非HTML版本会有多好用。我能直接从客户端Java代码中使用GWT-RPC吗?
3. 使用其他形式的RPC。有什么建议吗?

1
虽然不是完整的答案,但是Java确实可以很好地处理Json,但是在PlayN下所有好的Json库都无法使用。今天我刚发布了一个问题,因为我们正在使用Jersey和EE堆栈中的其他一些东西构建我们的服务器作为无状态REST应用程序。http://stackoverflow.com/questions/9045455/how-do-i-convert-a-pojo-to-json-in-playn 这使我们能够共享DTO并具有类型安全的回调和转换。 使用您的GWT方法可能会破坏Java构建,然后您可以坚持使用GWT并为其使用一些画布框架。 - iuiz
1个回答

12

针对Java和Android平台上的GWT RPC,我目前正在尝试使用gwt-syncproxy为Java客户端提供访问GWT RPC方法的服务,并在它们各自的目标平台上使用Guice、Gin和RoboGuice来注入相应的异步服务实例以实例化Game对象。

对于PlayN项目的core/pom.xml文件,我包含以下依赖坐标来支持需要的Gin/Guice/RoboGuice依赖注入:

<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>

然后我向具体的游戏实现中添加@Inject注释到任何字段:

public class TestGame implements Game {

    @Inject
    TestServiceAsync _testService;

    ...

}
在html/pom.xml中,我包含了Gin的依赖坐标:
<dependency>
  <groupId>com.google.gwt.inject</groupId>
  <artifactId>gin</artifactId>
  <version>1.5.0</version>
</dependency>

我创建了TestGameGinjector和TestGameModule类:

TestGameGinjector.java

@GinModules(TestGameModule.class)
public interface TestGameGinjector extends Ginjector {
    TestGame getGame();
}

测试游戏模块.java

public class TestGameModule extends AbstractGinModule {
    @Override
    protected void configure() {
    }
}

目前,我只是注入TestServiceAsync接口,因此无需在TestGameModule.configure()方法中添加任何实现;Gin通过GWT.create()管理AsyncServices的实例化。

然后,我将以下内容添加到TestGame.gwt.xml文件中

<inherits name='com.google.gwt.inject.Inject'/>

最后,我对TestGameHtml.java做出了以下更改。

public class TestGameHtml extends HtmlGame {

    private final TestGameGinjector _injector = GWT.create(TestGameGinjector.class);

    @Override
    public void start() {
        HtmlPlatform platform = HtmlPlatform.register();
        platform.assetManager().setPathPrefix("test/");
        PlayN.run(_injector.getGame());
    }
}

这基本上涵盖了PlayN的HTML5平台。

对于Java平台,我将以下依赖坐标添加到java/pom.xml中:

<dependency>
  <groupId>com.gdevelop.gwt.syncrpc</groupId>
  <artifactId>gwt-syncproxy</artifactId>
  <version>0.4-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>com.google.inject</groupId>
  <artifactId>guice</artifactId>
  <version>3.0-rc2</version>
</dependency>

请注意,Google Code上的gwt-syncproxy项目不包含pom.xml文件。 我已经将gwt-syncproxy进行了“Maven化”,并通过git在https://bitbucket.org/hatboyzero/gwt-syncproxy.git上提供了一个分支版本。 您可以克隆它,然后运行 mvn clean package install 将其安装到您本地的Maven仓库中。

无论如何,我为Java平台创建了一个名为TestGameModule.java的文件,内容如下:

public class TestGameModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(TestServiceAsync.class).toProvider(TestServiceProvider.class);
    }

    public static class TestServiceProvider implements Provider<TestServiceAsync> {
        public TestServiceAsync get() {
            return (TestServiceAsync) SyncProxy.newProxyInstance(
                TestServiceAsync.class,
                Deployment.gwtWebPath(),  // URL to webapp -- http://127.0.0.1:8888/testgame
                "test"
            );
        }
    }
}

我将TestGameJava.java文件修改如下:

public class TestGameJava {

    public static void main(String[] args) {
        Injector _injector = Guice.createInjector(new TestGameModule());

        JavaPlatform platform = JavaPlatform.register();
        platform.assetManager().setPathPrefix("test/images");
        PlayN.run(_injector.getInstance(TestGame.class));
    }
}

我曾经在Android平台上使用RoboGuice进行类似的尝试--不进入太多细节,相关的更改/片段如下:

pom.xml依赖项

<dependency>
  <groupId>com.gdevelop.gwt.syncrpc</groupId>
  <artifactId>gwt-syncproxy</artifactId>
  <version>0.4-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>org.roboguice</groupId>
  <artifactId>roboguice</artifactId>
  <version>1.1.2</version>
</dependency>

<dependency>
  <groupId>com.google.inject</groupId>
  <artifactId>guice</artifactId>
  <version>3.0-rc2</version>
  <classifier>no_aop</classifier>
</dependency>

TestGameApplication.java

public class TestGameApplication extends RoboApplication {
    @Override
    protected void addApplicationModules(List<Module> modules) {
        modules.add(new TestGameModule());
    }
}

测试游戏模块.java

public class TestGameModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(TestServiceAsync.class).toProvider(TestServiceProvider.class);
    }

    public static class TestServiceProvider implements Provider<TestServiceAsync> {
        public TestServiceAsync get() {
            return (TestServiceAsync) SyncProxy.newProxyInstance(
                TestServiceAsync.class,
                Deployment.gwtWebPath(),  // URL to webapp -- http://127.0.0.1:8888/testgame
                "test"
            );
        }
    }
}

TestGameActivity.java

:测试游戏活动的Java文件。
public class TestGameActivity extends GameActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    final Injector injector = ((RoboApplication) getApplication()).getInjector();
        injector.injectMembers(this);
        super.onCreate(savedInstanceState);
    }

    @Override
    public void main(){
        platform().assetManager().setPathPrefix("test/images");
        final Injector injector = ((RoboApplication) getApplication()).getInjector();
        PlayN.run(injector.getInstance(TestGame.class));
    }
}
那是我如何在项目中使用Gin/Guice/RoboGuice + GWT的快速简要介绍,我已经验证它在Java和HTML平台上都可以完美运行。无论如何,这就是提供RPC调用到多个PlayN平台的GWT方法 :)。

1
我已经更新了我的答案,因为最近我成功解决了许多关于如何做到这一点的问题... - hatboyzero
听起来我可以使用GWT RPC来完成我的工作,并在需要支持非HTML输出模式时采用这种方法。感谢您详细的回复! - Mark Schmit
没问题 - 很高兴为您服务 :) - hatboyzero
1
非常好的答案!感谢您的发布! - Chii
有没有iOS平台的实现? - Majid Laissi
你把 TestServiceTestServiceAsync 接口放在哪里?是在 html 还是在 core 中?我认为它们应该在 core 中,因为它们在不同平台之间是通用的,但是 com.google.gwt.user.client.rpc.RemoteService 只能在 html 中使用,而不能在 core 中使用。 - Jon Newmuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接