@zxiy: Eclipse的工作空间目录中到底有啥?

因为试验了不少稀奇古怪的IDE,项目目录中充满了各种莫名其妙的文件。于是上周六走之前我把所有的项目文件都删了然后重新gclient了一份,用sbt编译通过就走人了。

这周一上来,我重新创建了Eclipse项目文件,然后导入工作空间,Eclipse就编译不通过了。

本来这是常见的事,然后我依次尝试了以前遇到这个情况之后成功解决的方法:

  • 刷新&clean

  • 重启Eclipse

  • 关闭项目重新打开

  • Eclipse中删除项目重新载入

  • 取消所有项目依赖关系再重新勾上

  • 关掉Eclipse,sbt重新编译再打开

  • @Atry 提供的方法,Remove scala nature然后再加回来以及修改编译选项再改回去

然后都失败了。

最后我打开了老的demo项目qforce-server-demo-1的工作空间(工作空间目录和项目目录不在同一个目录),从eclipse移除所有项目,再载入手游服务器的项目文件,就好了。

这样看,Eclipse的工作空间中肯定包含了某些关于编译或者其他的设置,影响了我们是否可以成功编译。等有时间研究下到底是什么东西造成了这样的结果。

Update 10.16: 昨天研究了一下,怀疑是编译顺序导致的问题,但是上次的问题无法重现了,只能凭靠猜测了。这个选项在Eclipse的Window -> Preferences -> General -> Workspace -> Build Order里面设置。默认的选项似乎是项目名字典序,但是会用某种方法来解决其依赖关系。

我将entity从Build Order中移除,编译过程中一度出现了和之前一样的错误信息,但这些错误信息在最后还是被清除掉了(貌似通过依赖关系找到了被依赖项目?)建议下次再碰到这个问题的同学试下修改Build Order能否解决这个问题。

@Atry: 管道

Stateless Future现在可以支持管道了: https://github.com/qifun/stateless-future-util/blob/master/src/main/scala/com/qifun/statelessFuture/util/Pipe.scala

  • 线程安全
  • 基于Lock-free算法
  • 可以用来实现复杂的状态机

@chank 上周说定时器逻辑太难写,现在用管道做个状态机就行了。

实现管道时,我发现Future宏的尾调用优化做得还不够好,于是重构了Future宏,现在尾调用优化很完美了: https://github.com/qifun/stateless-future/commit/9527b52fba29249561fb3625e3e36d0ddb860c91

@chank: linux 内存使用率

使用top命令查看linux内存使用率的时候发现used的内存很多,free的内存很少,而看应用程序%MEM的内存使用率却很少

原来其实是linux的内存使用策略跟windows的不同

linux 会尽可能多地利用内存来提高系统的性能,因此linux会把很大一部分内存用作文件缓存

只有在应用程序需要内存的时候才会从cached缓存中分配内存给应用程序

在top命令中看到的cached Mem就是文件元数据和文件缓存,而buffers则主要是目录元数据缓存

因此应用程序总共使用的内存应该是:total-free-cached-buffers

@chank: 项目依赖provided

把项目之间的依赖关系标为”provided”意味着在编译期才需要被依赖的项目,发布后就不再包含被依赖的项目了,被依赖的项目由运行期环境提供

例如json-stream-bson对json-stream的provided依赖表示在编译json-stream-bson时使用了json-stream,但发布之后就没有包含json-stream的代码了,在.sbt文件中的设置如下

库依赖:

libraryDependencies += "com.qifun" %% "json-stream" % "0.2.0-SNAPSHOT" % "provided"

对应的项目间依赖:

lazy val `json-stream-bson` = project dependsOn (`json-stream` % "provided")

通过这样设置项目之间的依赖关系就不需要在打包paraiso项目时使用sbt-assembly的first合并策略了。

ps: sbt-assembly的first在合并相同文件时是跟声明顺序有关的,使用的是第一个被声明依赖项目的文件

@chank: 项目依赖管理

这周使用了sbt-sonatype来支持我们的项目自动发布项目到maven仓库

使用Java或Scala都会经常听到maven和ivy,那么它们究竟是什么呢?

查了下,原来Apache Maven是项目项目管理和自动构建的工具,它提供了管理项目依赖、测试、打包并且发布项目到仓库等一大堆功能,比较重量级。而它管理管理项目依赖用的是项目对象模型(pom)。使用pom.xml文件来定义

而Apache Ivy则只是一个依赖管理工具(是Apache Ant的一个子项目),它也是通过ivy.xml文件来定义的,比较轻量级一点。

在sbt中使用的就是Ivy来管理项目依赖的,但使用特定的领域专用语言(DSL)来描述依赖关系的,即libraryDependencies的语法。当然也可以用maven的pom.xml或ivy的ivy.xml文件来描述项目之间的依赖关系。

具体可参考: https://www.packtpub.com/books/content/dependency-management-sbt

@tice9982: 二维表关联

在项目里,有很多和等级有关的数据,如:角色等级、物品等级、声望等级、帮派等级等;除了等级以外还有其它的属性像:职业、军衔、性别等。

如果在不同等级里,不同的军街,组成一个二维表。又需要在xlsx里定义等级和军街的数据.如下两个表格,这个应该怎么定义?

  • 怎么在项目里通过配置更新等级数据
  • 怎么让“军街” “等级”这两个表自动关联起来,可以让策划可以动态添加军街、等级这两个表的内容
……junxian1junxian2junxian3
dengji1……………………
dengji2……………………
dengji3……………………
  //
junxian1相关数据
junxian2……
junxian3……

现在在帮派里是下面的这样处理,军街变成了列,觉得不是太好。同时添加了一个next 用来修改类对象中的等级数据,也很别扭。

……nextjunxian1junxian2junxian3
dengji1……dengji2………………
dengji2……dengji3………………
dengji3…………………………

@zxiy 配置表设计的经验总结

配置表设计时最重要的是什么呢? 个人认为是0冗余。

我们制订的的各种规则,很大一部分是为了减少人肉上的出错而制定的,让配置表低冗余甚至0冗余就是其中之一。

其实说起来,数据的冗余还有一些好处,比如提高运行速度之类。但为了减少在把一份数据往不同的地方填写,或者更容易出错的修改(改了一个地方另一个地方忘了,并且后接手的人不一定知道一份数据的所有位置)时造成的错误,我们在做人肉填写的数据表时,就要减少冗余。

怎么减少冗余呢,根据最近的经验,就是找准依赖关系,找准依赖关系,还有找准依赖关系,然后就为被依赖的东西作为行建一张表,当然,如果这样做太过反人类可以再去跟策划沟通酌情考虑一下。

举个例子,地图上有很多点,部分点是副本,一个副本是由N个小副本(关卡)组成的,然后我是这样做的:

为地图上的点建一张表,

点的类型建一张表,然后作为地图上点的字段。因为这是点的属性,它是城镇还是副本取决于这个点是什么。

然后为这个大副本建一张表,而这个大副本本身的名字,就是地图点类型的字段了,可以做为构造函数参数。

然后副本中的每一个小副本单独一张表,它依赖于啥?当然是依赖于这个大副本了,当作大副本的字段。

这样,就差不多好了。0冗余,除了改行ID本身,改任何一个字段都不会发生改一个数据却需要改多处的情况。

而在游戏的业务逻辑之中可能会需要反向查询其依赖关系,为了避免每次查询时的时间浪费,我们可以在程序中遍历配置表来建立一个全局常量表(静态常量)完成这方面的需求。

@zjhongxian: Spine使用要注意的一个小细节

Spine的SkeletonAnimation.skeleton.SetSkin之后要记得SetSlotsToSetupPose,否则Spine的DrawOrder会不正常,Attachment也不对。

@zjhongxian: Spine的动画管理:

关键看SetAnimation(int trackIndex, String animationName, bool loop) 和 AddAnimation(int trackIndex, String 

animationName, bool loop, float delay) 函数。他们的区别是:1直接设置当前trackIndex的动画为animationName(并把之前同层的

往前挪),2是往当前trackIndex后面添加animationName相关的trackEntry。

trackIndex越大的动画,在更新的时候就越在后面。看AnimationState的Apply函数里面的一句: for (int i = 0; i < tracks.Count; i++)  {...}
这样就意味着trackIndex大的动画就会覆盖trackIndex小的动画。用途示例: 把Idle动画设置为0层的,walk动画设置为1层的,当walk停止的时候,动画就自动切换到了Idle状态。

小报

岂凡技术小报