《万国觉醒》之游戏战报FreeMarker模板引擎实现

简介: 《万国觉醒》之游戏战报FreeMarker模板引擎实现

这两天在玩《万国觉醒》,看了下战报,每一回合伤害,技能,buf明细都写的很详尽,如果自己去实现,该怎么做呢?

战报如下:

想想,只要有个记录战斗明细的对象+模板引擎,一整合,需要的结果就出来了,就拿接口很丰富的freemarker练手。

好,我们先来学习下这个模板引擎的基础知识。

一、FreeMarker 是什么?

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

二、使用步骤

1.引入库

implementation group: 'org.freemarker', name: 'freemarker', version: '2.3.31';

2.使用

1.数字格式化(金额格式化)

${num?string('0.00')}
如果小数点后不足两位,用 0 代替
${num?string('#.##')}
如果小数点后多余两位,就只保留两位,否则输出实际值
输出为:1239765.46
${num?string(',###.00')}
输出为:1,239,765.46
整数部分每三位用 , 分割,并且保证小数点后保留两位,不足用 0 代替
${num?string(',###.##')}
输出为:1,239,765.46
整数部分每三位用 , 分割,并且小数点后多余两位就只保留两位,不足两位就取实际位数,可以不不包含小数点
${num?string('000.00')}
输出为:012.70
整数部分如果不足三位(000),前面用0补齐,否则取实际的整数位
${num?string('###.00')}
等价于
${num?string('#.00')}
输出为:12.70
整数取实际的位数

2.时间字段格式化

时间:${(startTime?string("MM/dd HH:mm"))!}-${(endTime?string("MM/dd HH:mm"))!}

生成后就展现如下:

时间:06/09/ 10:18-06/09/ 10:18

3.千分位去除

${total?c}

4.如何使用枚举

java 字段 为 private PhaseEnum phase;

public enum PhaseEnum {
    /**
     * 未处理
     */
    UN_RESOLVED(0, "未处理"),
    /**
     * 处理中
     */
    PROCESSING(1, "处理中"),
    /**
     * 已处理
     */
    RESOLVED(2, "已处理"),
    /**
     * 忽略
     */
    OMIT(3, "忽略"),
    ;
    private final int id;
    private final String message;
    PhaseEnum(int id, String message) {
        this.id = id;
        this.message = message;
    }
    public int getId() {
        return id;
    }
    public String getMessage() {
        return message;
    }
}

使用

${phase.message}
<#if phase == "UN_RESOLVED">[领取]<#else>[查看]</#if>
${phase}

结果为:

未处理
[领取]
UN_RESOLVED

5.if else

<#if (winner?exists)>
  [${winner.mainHero.name}](${winner.total?c})的部队正高举武器,欢庆胜利!
<#else>
  双方均全军覆没!
</#if>

6.switch case

只能用字符串或者数字为值

7.基本运算

战斗结果:${(round.one.after-round.one.before)?c}

8.声明变量

<#assign name="张三"/>

9.比较大小

<#if (operation.one.loss>0)>  
</#if>

10.获取列表大小

${one.array?size}

如果加在if条件

<#if (one.array?size>0)>
    <#list one.array as buff>
${buff.desc}
    </#list>
<#elseif (one.array?size>10)>
//....
<#else>
无临时增益
</#if>

11.断字符串是否相等

<#if (appVersion=="0.0.0.0")>
</#if>

12.特殊字符用noparse转义

比如 < 符号

<#noparse><</#noparse>

如果程序运行在标准时区,如何让freemarker 显示东八区时区的时间

在文件头加上

<#setting time_zone="Asia/Shanghai">

13.转义字符有哪些?

转义序列 含义
\ " 引号 (u0022)
\ ’ 单引号(又称为撇号) (u0027)
\ { 起始花括号:{
\ \ 反斜杠 (u005C)
\n 换行符 (u000A)
\r 回车 (u000D)
\t 水平制表符(又称为tab) (u0009)
\b 退格 (u0008)
\f 换页 (u000C)
\l 小于号:<
\g 大于号:>
\a &符:&
\xCode 字符的16进制 Unicode 码 (UCS 码)

14.字符串填充,适合用于建文本表格

left_pad,right_pad

id       |     command name                      |average size    |   max size         |  total size      |invoke time
--------------------------------------------------------------------------------------------------------------------------------
<#list array as command>
${command.code?c?right_pad(10)}${command.name?right_pad(40)}${command.avgSize?c?right_pad(20)} ${command.maxSize?c?right_pad(20)}${command.totalSize?c?right_pad(20)}${command.invokeTimes?c?right_pad(20)}
</#list>

获得的结果如下:

id       |     command name                      |average size    |   max size         |  total size      |invoke time
--------------------------------------------------------------------------------------------------------------------------------
6         EntityNtfMsg                            123                  918                 21913               178                 
120       Player_UpdateView_C2S                   41                   42                  1760                42                  
121       Player_UpdateView_S2C                   0                    0                   0                   42                  
42        Player_ChangeArmyAction_C2S             24                   24                  48                  2                   
43        Player_ChangeArmyAction_S2C             0                    0                   0                   2                   
126       Player_SearchWalkPath_C2S               20                   20                  40                  2                   
127       Player_SearchWalkPath_S2C               37                   52                  74                  2                   
7         Login_C2S_Msg                           44                   44                  44                  1                   
8         Login_S2C_Msg                           23                   23                  23                  1                   
11        KeepAlive_C2S_Msg                       0                    0                   0                   1                   
12        KeepAlive_S2C_Msg                       7                    7                   7                   1                   
32        Player_GetDebugCommandList_C2S          2                    2                   2                   1                   
33        Player_GetDebugCommandList_S2C          635                  635                 635                 1                   
55        Player_ChangeMap_S2C                    5                    5                   5                   1                   
150       Player_SearchMonster_C2S                2                    2                   2                   1                   
151       Player_SearchMonster_S2C                12                   12                  12                  1

15.对LocalDateTime 的支持

implementation group: 'no.api.freemarker', name: 'freemarker-java8', version: '2.1.0';

添加对对于JDK8的支持配置类

Configuration config = new Configuration(Configuration.VERSION_2_3_31);
config.setObjectWrapper(new Java8ObjectWrapper(Configuration.VERSION_2_3_31));

使用

${startTime.format('yyyy-MM-dd HH:mm:ss')}

要对时区进行设置的话,就要做如下的处理:

<#setting time_zone="Asia/Shanghai">
**统计日期**:<font color='comment'>${startTime.toZonedDateTime(time_zone).format('yyyy-MM-dd HH:mm:ss')} - ${endTime.toZonedDateTime(time_zone).format('yyyy-MM-dd HH:mm:ss')} </font>

综合使用

战斗日志
时间:${(startTime?string("MM/dd HH:mm:ss"))!}-${(endTime?string("MM/dd HH:mm:ss"))!}
地点:X:${x?c} Y:${y?c}
战斗简介
${one.name}[${one.mainHero.name}]和${other.name}[${other.mainHero.name}]在野外发生了遭遇战!
我方阵容
${one.name} [${one.mainHero.name}]等级${one.mainHero.level} <#if (one.deputyHero?exists)>&[${one.deputyHero.name}]等级${one.deputyHero.level}</#if>兵力:${one.total?c}
<#if (one.array?size>0)>
    <#list one.array as buff>
${buff.desc}
    </#list>
<#else>
无临时增益
</#if>
敌方阵容
${other.name} [${other.mainHero.name}]等级${other.mainHero.level} <#if (other.deputyHero?exists)>&[${other.deputyHero.name}]等级${other.deputyHero.level}</#if>兵力:${other.total?c}
<#if (other.array?size>0)>
    <#list other.array as buff>
        ${buff.desc}
    </#list>
<#else>
无临时增益
</#if>
<#list array as round>
第${round.id}回合
    <#if (round.one?exists)&&(round.other?exists)>
[我方]兵力:${round.one.before?c},战斗结果:${(round.one.after-round.one.before)?c}
[敌方]兵力:${round.other.before?c},战斗结果:${(round.other.after-round.other.before)?c}
    <#list round.one.array as buff>
[${round.one.name}](${round.one.before?c})由于[${buff.name}]效果${buff.desc},${buff.message}
    </#list>
    <#list round.other.array as buff>
[${round.other.name}](${round.other.before?c})由于[${buff.name}]效果${buff.desc},${buff.message}
    </#list>
    <#list round.array as operation>
        <#if (operation.one?exists)>
            <#if (operation.one.skillVO?exists)>
[${operation.one.attacker.name}](${operation.one.total?c}) 发动了[${operation.one.skillVO.skillName}]!
                <#if (operation.one.loss>0)>
[${operation.one.defencer.name}]损失了${operation.one.loss?c}兵力
                </#if>
                <#list operation.one.skillVO.array as buff>
                    <#if (operation.one.id==buff.sourceId)>
[${operation.one.attacker.name}]的部队获得了${buff.name}效果加成,${buff.message}
                    <#else>
[${operation.one.defencer.name}]的部队获得了${buff.name}效果加成,${buff.message}
                    </#if>
                </#list>
            <#else>
                <#if (operation.one.loss>0)>
[${operation.one.attacker.name}](${operation.one.total?c})对[${operation.one.defencer.name}]发起了普通攻击,[${operation.one.defencer.name}]损失了${operation.one.loss?c}兵力
                </#if>
            </#if>
        </#if>
        <#if (operation.other?exists)>
            <#if (operation.other.loss>0)>
[${operation.other.attacker.name}]发动反击,[${operation.other.defencer.name}]损失了${operation.other.loss?c}兵力
            </#if>
        </#if>
    </#list>
    <#else>
本回合交战双方都没有发生战斗!
    </#if>
    ------------------------------------------------------------------------------
</#list>
战斗结束
<#switch endType.name()>
    <#case "BOT_END">
        <#if (winner?exists)>
[${winner.mainHero.name}](${winner.total?c})的部队正高举武器,欢庆胜利!
        <#else>
双方均全军覆没!
        </#if>
        <#break>
    <#case "BOT_OUT_OF_ROUND">
由于一方撤退,两军不再交战!
        <#break>
    <#case "BOT_OUT_OF_HIDDEN">
由于一方隐藏,两军不再交战!
        <#break>
    <#default>
战斗结束!
</#switch>

整合后的文字战报如下:

战斗日志
时间:06/10 11:51:44-06/10 11:52:35
地点:X:13478 Y:12852
战斗简介
玩家名[项羽]和玩家名[谭雅]在野外发生了遭遇战!
我方阵容
玩家名 [项羽]等级1 兵力:2294
敌方阵容
玩家名 [谭雅]等级1 兵力:7000
第1回合
[我方]兵力:2294,战斗结果:-48
[敌方]兵力:7000,战斗结果:-85
[项羽](2294)对[谭雅]发起了普通攻击,[谭雅]损失了42兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](7000)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了43兵力
    ------------------------------------------------------------------------------
第2回合
[我方]兵力:2246,战斗结果:-48
[敌方]兵力:6915,战斗结果:-86
[项羽](2246)对[谭雅]发起了普通攻击,[谭雅]损失了44兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](6915)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了42兵力
    ------------------------------------------------------------------------------
第3回合
[我方]兵力:2198,战斗结果:-48
[敌方]兵力:6829,战斗结果:-84
[项羽](2198)对[谭雅]发起了普通攻击,[谭雅]损失了42兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](6829)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了42兵力
    ------------------------------------------------------------------------------
第4回合
[我方]兵力:2150,战斗结果:-48
[敌方]兵力:6745,战斗结果:-84
[项羽](2150)对[谭雅]发起了普通攻击,[谭雅]损失了42兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](6745)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了42兵力
    ------------------------------------------------------------------------------
第5回合
[我方]兵力:2102,战斗结果:-48
[敌方]兵力:6661,战斗结果:-82
[项羽](2102)对[谭雅]发起了普通攻击,[谭雅]损失了42兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](6661)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了40兵力
    ------------------------------------------------------------------------------
第6回合
[我方]兵力:2054,战斗结果:-47
[敌方]兵力:6579,战斗结果:-83
[项羽](2054)对[谭雅]发起了普通攻击,[谭雅]损失了42兵力
[谭雅]发动反击,[项羽]损失了23兵力
[谭雅](6579)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了41兵力
    ------------------------------------------------------------------------------
第7回合
[我方]兵力:2007,战斗结果:-47
[敌方]兵力:6496,战斗结果:-81
[项羽](2007)对[谭雅]发起了普通攻击,[谭雅]损失了40兵力
[谭雅]发动反击,[项羽]损失了23兵力
[谭雅](6496)对[项羽]发起了普通攻击,[项羽]损失了24兵力
[项羽]发动反击,[谭雅]损失了41兵力
    ------------------------------------------------------------------------------
第8回合
[我方]兵力:1960,战斗结果:-46
[敌方]兵力:6415,战斗结果:-81
[项羽](1960)对[谭雅]发起了普通攻击,[谭雅]损失了40兵力
[谭雅]发动反击,[项羽]损失了23兵力
[谭雅](6415)对[项羽]发起了普通攻击,[项羽]损失了23兵力
[项羽]发动反击,[谭雅]损失了41兵力
    ------------------------------------------------------------------------------
第9回合
[我方]兵力:1914,战斗结果:-47
[敌方]兵力:6334,战斗结果:-78
[项羽](1914)对[谭雅]发起了普通攻击,[谭雅]损失了39兵力
[谭雅]发动反击,[项羽]损失了24兵力
[谭雅](6334)对[项羽]发起了普通攻击,[项羽]损失了23兵力
[项羽]发动反击,[谭雅]损失了39兵力
    ------------------------------------------------------------------------------
第10回合
[我方]兵力:1867,战斗结果:-46
[敌方]兵力:6256,战斗结果:-79
[项羽](1867)对[谭雅]发起了普通攻击,[谭雅]损失了39兵力
[谭雅]发动反击,[项羽]损失了23兵力
[谭雅](6256)对[项羽]发起了普通攻击,[项羽]损失了23兵力
[项羽]发动反击,[谭雅]损失了40兵力
.....
.....
    ------------------------------------------------------------------------------
第52回合
[我方]兵力:18,战斗结果:-18
[敌方]兵力:3891,战斗结果:-3
[项羽](18)由于[万箭齐发]效果全军攻击力增强10%,剩余4回合
[谭雅](3891)由于[万箭齐发]效果全军攻击力增强10%,剩余4回合
[项羽](18)对[谭雅]发起了普通攻击,[谭雅]损失了3兵力
[谭雅]发动反击,[项羽]损失了18兵力
    ------------------------------------------------------------------------------
战斗结束
[谭雅](3888)的部队正高举武器,欢庆胜利!

总结

以上都是制作游戏战报的过程中的一些总结,大家也可以用其他模板引擎去做实现。

参考链接:

freemarker在线手册

目录
相关文章
|
6月前
|
前端开发 JavaScript 开发者
水墨代码:前端川的诞生——在夏日阴雨中启航
【前端川】网站于农历五月初一(2024年6月6日)上线,融合水墨画与现代前端技术,呈现独特的水墨代码美学。创建者陈川分享技术心得与实战经验,网站特色包括水墨风格界面、技术深度解析及实战案例。在夏日雨中启航,"前端川"致力于为开发者提供灵感与帮助,探索前端技术的无限可能。
109 17
星际争霸之小霸王之小蜜蜂(十六)--狂奔的花猫
星际争霸之小霸王之小蜜蜂(十六)--狂奔的花猫
星际争霸之小霸王之小蜜蜂(十三)--接着奏乐接着舞
星际争霸之小霸王之小蜜蜂(十三)--接着奏乐接着舞
|
4月前
|
前端开发 JavaScript UED
JSF 携手 jQuery 上演奇幻大戏,颠覆 Web 开发世界,你敢错过吗?
【8月更文挑战第31天】在Web开发领域,JavaServer Faces(JSF)与jQuery均是不可或缺的强大工具。JSF以组件为基础进行开发,而jQuery则以高效简洁的DOM操作及丰富的插件库著称。结合两者,能为Web应用注入新活力,实现复杂交互与动态效果。通过引入jQuery库并集成至JSF应用中,可轻松实现如动画、表单验证等功能,提升用户体验。本文通过具体示例展示了如何利用jQuery增强JSF应用,包括页面元素的动态显示与隐藏等效果,使开发过程更为便捷高效,激发更多创意可能。
20 0
|
4月前
|
Java 数据库 API
JSF与JPA的史诗级联盟:如何编织数据持久化的华丽织锦,重塑Web应用的荣耀
【8月更文挑战第31天】JavaServer Faces (JSF) 和 Java Persistence API (JPA) 分别是构建Java Web应用的用户界面组件框架和持久化标准。结合使用JSF与JPA,能够打造强大的数据驱动Web应用。首先,通过定义实体类(如`User`)和配置`persistence.xml`来设置JPA环境。然后,在JSF中利用Managed Bean(如`UserBean`)管理业务逻辑,通过`EntityManager`执行数据持久化操作。
63 0
|
4月前
|
前端开发 安全 Java
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
32 0
|
4月前
|
Java 测试技术 容器
从零到英雄:Struts 2 最佳实践——你的Web应用开发超级变身指南!
【8月更文挑战第31天】《Struts 2 最佳实践:从设计到部署的全流程指南》深入介绍如何利用 Struts 2 框架从项目设计到部署的全流程。从初始化配置到采用 MVC 设计模式,再到性能优化与测试,本书详细讲解了如何构建高效、稳定的 Web 应用。通过最佳实践和代码示例,帮助读者掌握 Struts 2 的核心功能,并确保应用的安全性和可维护性。无论是在项目初期还是后期运维,本书都是不可或缺的参考指南。
55 0
|
7月前
|
前端开发 JavaScript 搜索推荐
专业与传统相融,程序员特有祝福:通过前端代码送上新春祝福
新春佳节即将来临,忙了一年,作为程序员,当然要用属于程序员独有的方式来给大家送上新春祝福。在这个喜庆的时刻,让我们以技术的视角来送上一份特别的新春祝福,作为程序员,我们可以用代码和技术,为了大家带来一份独特而有趣的祝福,为了给节日增添一份属于技术人特有的魅力,以前端开发的视角来送上一份特别的新春祝福。作为前端开发者,通过编写前端代码可以创造出丰富多样的视觉效果,可以利用HTML、CSS和JavaScript等编写代码来呈现出直观的新春祝福效果,为大家呈现出生动直观的新春祝福。那么本文以前端程序员的视角,结合前端专业知识送上新春祝福,希望在新的一年里,大家的生活充满幸福和技术的收获。
98 1
专业与传统相融,程序员特有祝福:通过前端代码送上新春祝福
|
Web App开发 前端开发 JavaScript
前端的培训计划书
前端的培训计划书
108 1
|
移动开发 前端开发 数据可视化
前端叹了口气,并表示谣言止于智者
前端叹了口气,并表示谣言止于智者