@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里定义等级和军街的数据.如下两个表格,这个应该怎么定义?
- 怎么在项目里通过配置更新等级数据
- 怎么让“军街” “等级”这两个表自动关联起来,可以让策划可以动态添加军街、等级这两个表的内容
…… | junxian1 | junxian2 | junxian3 | |
dengji1 | …… | …… | …… | …… |
dengji2 | …… | …… | …… | …… |
dengji3 | …… | …… | …… | …… |
junxian1 | 相关数据 | //
junxian2 | …… |
junxian3 | …… |
现在在帮派里是下面的这样处理,军街变成了列,觉得不是太好。同时添加了一个next 用来修改类对象中的等级数据,也很别扭。
…… | next | junxian1 | junxian2 | junxian3 | |
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状态。