├── .github
└── workflows
│ └── commitTest.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_zh_CN.md
├── SyncBundles.java
├── assets
├── bundles
│ ├── bundle.properties
│ ├── bundle_de_DE.properties
│ ├── bundle_id_ID.properties
│ ├── bundle_ja.properties
│ ├── bundle_ru.properties
│ ├── bundle_zh_CN.properties
│ └── bundle_zh_TW.properties
├── config
│ └── mod_config.hjson
├── shaders
│ ├── dist_base.frag
│ └── entity_range.frag
└── sprites
│ └── ui
│ ├── background.9.png
│ ├── healthbar.9.png
│ ├── icons
│ ├── helium.png
│ ├── java.png
│ ├── javascript.png
│ ├── network-error.png
│ ├── program.png
│ └── slots-back.png
│ └── shieldbar.9.png
├── build.gradle.kts
├── bundleInfo.properties
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── icon.png
├── ktstools
├── genReflectCstrWrap.kts
├── genReflectCstrs.kts
├── genReflectMetWrap.kts
└── genReflectMethods.kts
├── mod.hjson
├── preview_imgs
├── en
│ ├── attackRange.png
│ ├── blur-1.png
│ ├── blur-2.png
│ ├── configEntry.png
│ ├── configurePane.png
│ ├── control-button.png
│ ├── effectRange.png
│ ├── modBrowser.png
│ ├── modManager.png
│ ├── placement-fold.png
│ ├── placement-unfold.png
│ ├── quick-config-entry.png
│ ├── quick-config.png
│ └── statusDisplay.png
└── zh_CN
│ ├── attackRange.png
│ ├── blur-1.png
│ ├── blur-2.png
│ ├── configEntry.png
│ ├── configurePane.png
│ ├── control-button.png
│ ├── effectRange.png
│ ├── modBrowser.png
│ ├── modManager.png
│ ├── placement-fold.png
│ ├── placement-unfold.png
│ ├── quick-config-entry.png
│ ├── quick-config.png
│ └── statusDisplay.png
├── settings.gradle.kts
└── src
└── main
└── kotlin
└── helium
├── He.kt
├── HeConfig.kt
├── Helium.kt
├── graphics
├── BaseClipDrawable.kt
├── BaseStripDrawable.kt
├── Blur.kt
├── ClipDrawable.kt
├── DrawUtils.kt
├── EdgeLineStripDrawable.kt
├── FillStripDrawable.kt
├── HeShaders.kt
├── LazyDrawable.kt
├── NinePatchClipDrawable.kt
├── ScaledNinePatchClipDrawable.kt
├── ScreenSampler.kt
├── StripDrawable.kt
└── g2d
│ └── EntityRangeExtractor.kt
├── ui
├── HeAssets.kt
├── HeStyles.kt
├── UIUtils.kt
├── dialogs
│ ├── ConfigLayouts.kt
│ ├── HeModsDialog.kt
│ ├── ModConfigDialog.kt
│ └── modpacker
│ │ ├── MdtMetaGen.kt
│ │ ├── MetaGenerator.kt
│ │ ├── ModInfo.kt
│ │ └── PackModel.kt
├── elements
│ ├── HeCollapser.kt
│ ├── SwappableCell.kt
│ └── roulette
│ │ ├── Roulette.kt
│ │ ├── Strip.kt
│ │ ├── StripButton.kt
│ │ ├── StripElement.kt
│ │ └── StripWrap.kt
└── fragments
│ ├── entityinfo
│ ├── ConfigurableDisplay.kt
│ ├── EntityInfoDisplay.kt
│ ├── EntityInfoFrag.kt
│ ├── EntityInfoStyles.kt
│ └── displays
│ │ ├── DetailsDisplay.kt
│ │ ├── EntityRangeDisplay.kt
│ │ ├── HealthDisplay.kt
│ │ └── StatusDisplay.kt
│ └── placement
│ └── HePlacementFrag.kt
└── util
├── Downloader.kt
├── Formatter.kt
├── Geomtry.kt
├── Reflection.kt
├── Structs.kt
└── binds
├── CombineKeyListener.kt
├── CombineKeyTree.kt
└── CombinedKeys.kt
/.github/workflows/commitTest.yml:
--------------------------------------------------------------------------------
1 | name: Build Mod
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | buildJar:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Set up PATH
12 | run: |
13 | echo "${ANDROID_HOME}/build-tools/34.0.0" >> $GITHUB_PATH
14 | - name: Set up JDK 17
15 | uses: actions/setup-java@v1
16 | with:
17 | java-version: 17
18 | - name: Build mod jar
19 | run: |
20 | chmod +x ./gradlew
21 | ./gradlew deploy
22 | - name: Upload built jar file
23 | uses: actions/upload-artifact@v4
24 | with:
25 | name: ${{ github.event.repository.name }}
26 | path: build/libs/${{ github.event.repository.name }}.jar
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | /core/assets/mindustry-saves/
3 | /core/assets/mindustry-maps/
4 | /core/assets/bundles/output/
5 | /core/assets/.gifimages/
6 | /deploy/
7 | /desktop/packr-out/
8 | /desktop/packr-export/
9 | /desktop/mindustry-saves/
10 | /desktop/mindustry-maps/
11 | /desktop/gifexport/
12 | /core/lib/
13 | /ios/assets/
14 | /core/assets-raw/sprites/generated/
15 | /core/assets-raw/sprites_out/
16 | /annotations/build/
17 | /annotations/out/
18 | /net/build/
19 | /tools/build/
20 | /tests/build/
21 | /server/build/
22 | /test_files/
23 | /annotations/build/
24 | /desktop-sdl/build/
25 | desktop-sdl/build/
26 | /android/assets/mindustry-maps/
27 | /android/assets/mindustry-saves/
28 | /core/assets/gifexport/
29 | /core/assets/version.properties
30 | /core/assets/locales
31 | /ios/src/io/anuke/mindustry/gen/
32 | /core/src/io/anuke/mindustry/gen/
33 | ios/robovm.properties
34 | packr-out/
35 | *.gif
36 |
37 | version.properties
38 |
39 | .attach_*
40 | ## Java
41 |
42 | *.class
43 | *.war
44 | *.ear
45 | hs_err_pid*
46 | crash-report-*
47 | replay_pid*
48 |
49 | ## Robovm
50 | /ios/robovm-build/
51 |
52 | ## GWT
53 | /html/war/
54 | /html/gwt-unitCache/
55 | .apt_generated/
56 | .gwt/
57 | gwt-unitCache/
58 | www-test/
59 | .gwt-tmp/
60 |
61 | ## Android Studio and Intellij and Android in general
62 | /android/libs/armeabi/
63 | /android/libs/armeabi-v7a/
64 | /android/libs/arm64-v8a/
65 | /android/libs/x86/
66 | /android/libs/x86_64/
67 | /android/gen/
68 | .idea/
69 | *.ipr
70 | *.iws
71 | *.iml
72 | /android/out/
73 | com_crashlytics_export_strings.xml
74 |
75 | ## Eclipse
76 |
77 | .classpath
78 | .project
79 | .metadata/
80 | /android/bin/
81 | /core/bin/
82 | /desktop/bin/
83 | /html/bin/
84 | /ios/bin/
85 | /ios-moe/bin/
86 | *.tmp
87 | *.bak
88 | *.swp
89 | *~.nib
90 | .settings/
91 | .loadpath
92 | .externalToolBuilders/
93 | *.launch
94 |
95 | ## NetBeans
96 |
97 | /nbproject/private/
98 | /android/nbproject/private/
99 | /core/nbproject/private/
100 | /desktop/nbproject/private/
101 | /html/nbproject/private/
102 | /ios/nbproject/private/
103 | /ios-moe/nbproject/private/
104 |
105 | /build/
106 | /android/build/
107 | /core/build/
108 | /desktop/build/
109 | /html/build/
110 | /ios/build/
111 | /ios-moe/build/
112 |
113 | /nbbuild/
114 | /android/nbbuild/
115 | /core/nbbuild/
116 | /desktop/nbbuild/
117 | /html/nbbuild/
118 | /ios/nbbuild/
119 | /ios-moe/nbbuild/
120 |
121 | /dist/
122 | /android/dist/
123 | /core/dist/
124 | /desktop/dist/
125 | /html/dist/
126 | /ios/dist/
127 | /ios-moe/dist/
128 |
129 | /nbdist/
130 | /android/nbdist/
131 | /core/nbdist/
132 | /desktop/nbdist/
133 | /html/nbdist/
134 | /ios/nbdist/
135 | /ios-moe/nbdist/
136 |
137 | nbactions.xml
138 | nb-configuration.xml
139 |
140 | ## Gradle
141 |
142 | /local.properties
143 | .gradle/
144 | gradle-app.setting
145 | /build/
146 | /android/build/
147 | /core/build/
148 | /desktop/build/
149 | /html/build/
150 | /ios/build/
151 | /ios-moe/build/
152 |
153 | ## OS Specific
154 | .DS_Store
155 | Thumbs.db
156 | android/libs/
157 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Helium
2 |
3 | > **点击[>> 这里 <<](README_zh_CN.md)查看中文文档**
4 |
5 |
6 |
7 |
8 | A Mindustry UI optimization mod that provides aesthetic enhancements and a more intuitive interface to improve gameplay experience.
9 |
10 | ### Core Features
11 |
12 | Currently in early development with primary features including:
13 |
14 | - **Default Dialog Background Blur (Frosted Glass Effect)**
15 |
16 | The Helium mod introduces an elegant blurred transparent background for in-game dialogs (currently dynamic frosted glass effect, with potential plans for static blur backgrounds if optimization demands arise)
17 |
18 | 
19 | 
20 |
21 | - **In-Game Entity Information Components**
22 |
23 | Provides various UI elements for game entities including units and blocks:
24 |
25 | - **Health & Status Indicators**:
26 |
27 | Displays real-time status (health, shields) above units and entities. When shield stacks exceed max health, multi-layer shields with stack counters are shown.
28 |
29 | 
30 |
31 | - **Attack Range Indicators**:
32 |
33 | Units and turrets now visualize their attack ranges as translucent areas. Processed boundaries emphasize combined team range contours to prevent visual clutter, with subtle pulsating animations and chromatic borders.
34 |
35 | 
36 |
37 | - **Functional Block Effect Range Indicators**:
38 |
39 | Devices like Mend Projectors, Overdrive Projectors, and unit repair stations display effect ranges with distinctive colors.
40 |
41 | 
42 |
43 | Hold the control hotkey (default: Left Alt key on keyboards, or a toolbar button on Android devices) to display detailed information such as unit weapon attack angles and entity details (since optimization panels may disable hover info on block placement panels, holding the hotkey allows targeted selection):
44 |
45 | 
46 |
47 | All features can be configured via the quick settings panel to control visibility per team. Disabled teams will not display corresponding elements. Access the quick configuration tool via the panel button:
48 |
49 | 
50 |
51 | Configuration panel:
52 |
53 | 
54 |
55 | - **Enhanced Block Placement Panel**
56 |
57 | A refined block selection panel integrating a quick item bar and standardized tool buttons. The panel can be collapsed to show only the quick item bar and toolbar, minimizing HUD clutter.
58 |
59 | The quick item bar supports pagination and allows users to pin frequently used items for rapid access while the panel is collapsed.
60 |
61 | 
62 | 
63 |
64 | - **The better Mod Manager and Mod Browser**
65 |
66 | Reworked the Mods Manager and Mods Browser, now they looks more aesthetically pleasing and functional, you can normally open [Mods] page to open new Mod Manager when it enabled, now the mods manager looks like:
67 |
68 | 
69 | 
70 |
71 | ### Mod Configuration
72 |
73 | Added **_\[Helium Config]_** entry in game settings, providing modular control over all UI modifications:
74 |
75 | 
76 | 
77 |
78 | ### Development Roadmap
79 |
80 | Current Priorities:
81 | - [x] In-game information panel quick toggle controls
82 | - [ ] Enhanced HUD elements (wave info panel, block selection bar)
83 | - [x] (Partially complete) Improved quick-access item bar with smart recommendations
84 | - [x] Standardized quick toolbar for better UI button placement
85 | - [ ] Redesigned mod configuration interface
86 |
87 | Future Plans:
88 | - [ ] Static background blur implementation
89 | - [ ] Overhauled game settings interface
90 | - [ ] Quick Schematic panel
91 | - [ ] Performance-optimized attack/effect range indicators (lower quality variant)
--------------------------------------------------------------------------------
/README_zh_CN.md:
--------------------------------------------------------------------------------
1 | # Helium(氦)
2 |
3 |
4 |
5 |
6 | 一个Mindustry的UI优化mod,提供美化的和更加清晰的界面以优化游戏体验。
7 |
8 | ### 主要功能
9 |
10 | 目前较早期开发进度较低,主要包含功能:
11 |
12 | - **默认对话框背景模糊(毛玻璃效果)**
13 |
14 | 氦模组为游戏提供了一个更美观的对话框模糊透明背景(目前为动态毛玻璃,后续如果存在对优化的需求可能增加静态背景模糊的计划)
15 |
16 | 
17 | 
18 |
19 | - **游戏内实体信息显示组件**
20 |
21 | 氦模组还为游戏内的各类实体如单位和方块,提供了生命条,状态栏以及攻击范围指示器等部件
22 |
23 | - **生命及状态指示器**:
24 |
25 | 单位及大部分实体顶部会显示其当前状态,包括生命值,护盾值(当护盾叠加超过最大生命值时会显示为多层护盾,并附加一个护盾倍数指示护盾的层数)
26 |
27 | 
28 |
29 | - **攻击范围指示器**:
30 |
31 | 所有的单位和炮塔现在会将它们的攻击范围以一个透明区域显示出来,边界经过处理后会只强调同一队伍叠加的攻击范围的外缘轮廓,以避免过多的叠加使得画面混乱,各个单位/炮塔的攻击范围也会有一个不那么显眼的波动动画与带有色差的边界去指示出来
32 |
33 | 
34 |
35 | - **功能性方块效果范围指示器**:
36 |
37 | 诸如修复投影,超速投影以及单位的维修站等设备的左右范围会像攻击范围一样被显示出来,并且具有特定的颜色
38 |
39 | 
40 |
41 | 通过按住控制热键(默认为键盘左Alt,或者在安卓设备上是工具栏的按钮)显示更详细的信息,如单位武器的攻击角,单位的详细信息(由于优化面板会取消掉方块放置面板上的悬停信息,则可以通过按住控制热键来选中目标显示详细信息):
42 |
43 | 
44 |
45 | 所有功能均可通过快速配置面板配置其显示的队伍,被禁用的队伍则不会在对应功能上显示,快速设置工具通过快捷面板上的按钮打开:
46 |
47 | 
48 |
49 | 配置面板如下:
50 |
51 | 
52 |
53 | - **更好的方块放置面板**
54 |
55 | 一个更好的方块选择面板,集成了快速物品栏和更规范化的工具按钮表,寻常时可以折叠起来只显示快速物品栏和工具栏以减少HUD上的信息量。
56 |
57 | 快捷物品栏可翻页,可选择常用的物品放入其中,以便在选择栏折叠状态下快速选择需要的方块。
58 |
59 | 
60 | 
61 |
62 | - **更好的mod管理器和浏览器**
63 |
64 | 重做游戏的Mod管理器与浏览器,现在它看起来更美观且实用,在启用状态下打开[模组]页面即可进入新的管理界面,它现在看起来是这样的:
65 |
66 | 
67 | 
68 |
69 | ### 模组配置
70 |
71 | 游戏内设置菜单新增了一个 **_\[氦配置]_** 选项,该子栏目可以进入氦模组的相关配置界面,模组内所有对游戏界面的调整及优化均会模块化,并可便捷的在此处进行设置。
72 |
73 | 
74 | 
75 |
76 | ### 开发计划
77 |
78 | 目前的主要计划内容
79 |
80 | - [x] 局内信息面板快速切换操作
81 | - [ ] 更好的局内HUD(左上角波次信息,右下角的方块选择栏)
82 | - [x] (部分完成) 更好的快捷物品栏和智能推荐栏,将取代游戏本身的方块选择栏
83 | - [x] 更规范的快速工具栏,以更好的在游戏界面内放置操作按钮
84 | - [x] 重做mod设置界面
85 |
86 | 未来预期的开发计划
87 |
88 | - [ ] 静态的背景模糊
89 | - [ ] 重做游戏设置界面
90 | - [ ] 快速蓝图
91 | - [ ] 较低质量换取性能的攻击/效果范围指示器
92 |
--------------------------------------------------------------------------------
/SyncBundles.java:
--------------------------------------------------------------------------------
1 | import java.io.*;
2 | import java.util.ArrayList;
3 | import java.util.LinkedHashMap;
4 | import java.util.Locale;
5 | import java.util.regex.Pattern;
6 | import java.text.DateFormat;
7 | import java.util.Date;
8 | import java.nio.charset.StandardCharsets;
9 |
10 | public class SyncBundles{
11 | private static final Pattern matcher = Pattern.compile("\\\\\\n");
12 | public static final char SEP = '\\';
13 |
14 | public static void main(String[] args){
15 | Properties info = new Properties(new File("bundleInfo.properties"));
16 | String sourceLocale = info.get("source");
17 | String bundlesDir = info.get("bundlesDir").replace("/", File.separator);
18 | String modName = info.get("modName");
19 | Properties loc = new Properties();
20 | loc.read(info.getOrigin("targetLocales").replace("[", "").replace("]", "").replace(SEP + System.lineSeparator(), System.lineSeparator()));
21 | String[] locales = new String[loc.map.size()*2];
22 | int index = 0;
23 | for(Pair entry: loc.map.values()){
24 | locales[index] = entry.key.replace("en_US", "");
25 | locales[index+1] = entry.value;
26 | index += 2;
27 | }
28 |
29 | File source = new File(bundlesDir, "bundle" + (sourceLocale.isBlank() ? "": "_" + sourceLocale) + ".properties");
30 | Properties sourceBundle = new Properties();
31 | sourceBundle.read(source);
32 |
33 | handleHeader(sourceBundle, modName, sourceLocale, args);
34 |
35 | sourceBundle.write(source);
36 | for(int i = 0; i < locales.length; i += 2){
37 | String locale = locales[i], mark = locales[i + 1];
38 | File file = new File(bundlesDir, "bundle" + (locale.isBlank() ? "": "_" + locale) + ".properties");
39 | Properties bundle = new Properties(sourceBundle, mark);
40 | if(file.exists()) bundle.read(file);
41 | handleHeader(bundle, modName, locale, args);
42 | bundle.write(file);
43 | }
44 | }
45 |
46 | public static void handleHeader(Properties source, String name, String locTag, String... args){
47 | source.put(name + ".mod.updateDate", DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.forLanguageTag(locTag.replace("_", "-"))).format(new Date()), 0);
48 |
49 | source.put(name + ".mod.version", args[0], 0);
50 | }
51 |
52 | public static class Properties{
53 | ArrayList lines = new ArrayList<>();
54 | LinkedHashMap map = new LinkedHashMap<>();
55 |
56 | String mark;
57 |
58 | public Properties(){}
59 |
60 | public Properties(File file){
61 | read(file);
62 | }
63 |
64 | public Properties(Properties source, String mark){
65 | this.mark = mark;
66 | for(Line line: source.lines){
67 | Line l;
68 | if(line instanceof Pair){
69 | l = new Pair(line.string, ((Pair) line).key, mark + " " + ((Pair) line).value);
70 | map.put(((Pair) l).key, (Pair) l);
71 | }
72 | else l = new Line(line.string);
73 | lines.add(l);
74 | }
75 | }
76 |
77 | public void put(String lineStr, int line){
78 | lines.add(line, new Line(lineStr));
79 | }
80 |
81 | public void put(String key, String value, int line){
82 | key = string2Unicode(key);
83 | String v = string2Unicode(value);
84 |
85 | Pair pair = map.computeIfAbsent(key, k -> {
86 | Pair r = new Pair(k + " = " + v, k, v);
87 | lines.add(line, r);
88 |
89 | return r;
90 | });
91 | pair.value = v;
92 | }
93 |
94 | public String get(String key){
95 | String str = map.containsKey(key)? map.get(key).value: null;
96 | StringBuilder result = new StringBuilder();
97 |
98 | for(String res: matcher.split(str)){
99 | result.append(res);
100 | }
101 |
102 | return result.toString();
103 | }
104 |
105 | public String getOrigin(String key){
106 | return map.containsKey(key)? map.get(key).value: null;
107 | }
108 |
109 | public void read(String content){
110 | read(new BufferedReader(new StringReader(content)));
111 | }
112 |
113 | public void read(File file){
114 | try{
115 | read(new BufferedReader(new FileReader(file)));
116 | }catch(FileNotFoundException e){
117 | e.printStackTrace();
118 | }
119 | }
120 |
121 | public void read(BufferedReader reader){
122 | try{
123 | String line;
124 | boolean init = lines.isEmpty();
125 | Pair last = null;
126 |
127 | while((line = reader.readLine()) != null){
128 | if(last != null){
129 | last.value = last.value + line;
130 |
131 | if(line.endsWith(String.valueOf(SEP))){
132 | last.value += System.lineSeparator();
133 | }
134 | else last = null;
135 |
136 | continue;
137 | }
138 |
139 | String[] strs = line.trim().split("=", 2);
140 | if(init){
141 | if(!strs[0].startsWith("#") && strs.length == 2){
142 | Pair p;
143 | lines.add(p = new Pair(line, strs[0].trim(), strs[1].trim()));
144 | map.put(p.key, p);
145 | if(strs[1].endsWith(String.valueOf(SEP))){
146 | last = p;
147 | p.value = p.value + System.lineSeparator();
148 | }
149 | }
150 | else{
151 | lines.add(new Line(line));
152 | }
153 | }
154 | else {
155 | if(strs.length != 2)
156 | continue;
157 | Pair pair = map.get(strs[0].trim());
158 | if(pair != null && !strs[1].trim().startsWith(mark)){
159 | pair.value = strs[1].trim();
160 | if(strs[1].endsWith(String.valueOf(SEP))){
161 | last = pair;
162 | pair.value += System.lineSeparator();
163 | }
164 | }
165 | }
166 | }
167 | }catch(IOException e){
168 | throw new RuntimeException(e);
169 | }
170 | }
171 |
172 | public void write(File file) {
173 | try {
174 | BufferedWriter writer = new BufferedWriter(new FileWriter(file, StandardCharsets.ISO_8859_1, false));
175 | for (Line line: lines) {
176 | writer.write(line.toString());
177 | writer.newLine();
178 | writer.flush();
179 | }
180 | } catch (IOException e) {
181 | throw new RuntimeException(e);
182 | }
183 | }
184 | }
185 |
186 | public static class Line{
187 | String string;
188 |
189 | public Line(String line){
190 | this.string = line;
191 | }
192 |
193 | @Override
194 | public String toString(){
195 | return string;
196 | }
197 | }
198 |
199 | public static class Pair extends Line{
200 | String key;
201 | String value;
202 |
203 | public Pair(String line, String key, String value){
204 | super(line);
205 | this.key = key;
206 | this.value = value;
207 | }
208 |
209 | @Override
210 | public String toString(){
211 | return key + " = " + value;
212 | }
213 | }
214 |
215 | private static String string2Unicode(String string) {
216 | StringBuilder unicode = new StringBuilder();
217 | for (int i = 0; i < string.length(); i++) {
218 | // 取出每一个字符
219 | char c = string.charAt(i);
220 | if (c<0x20 || c>0x7E) {
221 | // 转换为unicode
222 | String tmp = Integer.toHexString(c).toUpperCase();
223 | if (tmp.length() == 4) {
224 | unicode.append("\\u").append(tmp);
225 | } else if (tmp.length() == 3){
226 | unicode.append("\\u0").append(tmp);
227 | } else if (tmp.length() == 2){
228 | unicode.append("\\u00").append(tmp);
229 | } else {
230 | unicode.append("\\u000").append(tmp);
231 | }
232 | } else {
233 | unicode.append(c);
234 | }
235 | }
236 | return unicode.toString();
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/assets/bundles/bundle.properties:
--------------------------------------------------------------------------------
1 | he.mod.version = beta-0.6
2 | he.mod.updateDate = 2025 Jun 5
3 |
4 | settings.helium = Helium Config
5 | settings.category.basic = Basic Settings
6 | settings.category.keyBind = Key Bindings
7 | settings.category.debug = Debug Settings
8 |
9 | settings.basic.backBlur = Background Blur
10 | settings.item.enableBlur = Enable background blur
11 | settings.item.blurScl = Blur level
12 | settings.item.blurSpace = Blur strength
13 |
14 | settings.basic.entityInfo = In-game Entity Information
15 | settings.item.enableEntityInfoDisplay = Enable entity info display
16 | settings.item.enableHealthBarDisplay = Enable health bar
17 | settings.item.enableUnitStatusDisplay = Enable status effect display
18 | settings.item.enableRangeDisplay = Enable entity range display
19 | settings.item.showAttackRange = Show attack range
20 | settings.item.showHealRange = Show heal range
21 | settings.item.showOverdriveRange = Show overdrive range
22 | settings.item.entityInfoScale = Entity info showing scale
23 | settings.item.entityInfoAlpha = Entity info showing alpha
24 |
25 | settings.basic.placement = Placement Panel
26 | settings.item.enableBetterPlacement = Enable better placement panel
27 |
28 | settings.basic.modsDialog = Mods Manager
29 | settings.item.enableBetterModsDialog = Enable better mods dialog
30 |
31 | settings.debug.logging = Log Information
32 | settings.item.loadingInfo = Output loading info
33 |
34 | settings.keyBind.placement = Placement Panel
35 | settings.item.placementFoldHotKey = Fold/Unfold placement panel
36 | settings.item.switchFastPageHotKey = Switch inventory page
37 |
38 | settings.keyBind.entityInfo = In-game Entity Information
39 | settings.item.entityInfoHotKey = Entity info setting hotkey
40 |
41 | config.showAttackRange = Show attack range
42 | config.showHealRange = Show heal range
43 | config.showOverdriveRange = Show overdrive range
44 |
45 | dialog.mods.enabled = Enabled Mods
46 | dialog.mods.disabled = Disabled Mods
47 | dialog.mods.menu = Menu
48 | dialog.mods.upgradeAll = All Upgrades
49 | dialog.mods.checkUpdate = Check Update
50 | dialog.mods.checkFailed = Get failed
51 | dialog.mods.checkUpdateFailed = Check update failed
52 | dialog.mods.downloadFailed = Download failed
53 | dialog.mods.checkUpdating = Checking update
54 | dialog.mods.updateValid = An update available for this mod\nLatest version:{0}.
55 | dialog.mods.updateValidS = A valid update was found.
56 | dialog.mods.modStatCorrect = This mod was correctly loaded.
57 | dialog.mods.modStatError = This mod is invalid.
58 | dialog.mods.isLatest = Current is the latest version.
59 | dialog.mods.exportPack = Export ModPack
60 | dialog.mods.refresh = Refresh
61 | dialog.mods.importFav = Import Favorites
62 | dialog.mods.inputFavText = Input favorites text\uFF1A
63 | dialog.mods.exportFav = Export Favorites
64 | dialog.mods.favoritesText = Export favorites text\uFF1A
65 | dialog.mods.hideInvalid = Hide invalid mods
66 | dialog.mods.author = Author: {0}
67 | dialog.mods.version = Version\uFF1A{0}
68 | dialog.mods.jarMod = This mod contains Java program.
69 | dialog.mods.jsMod = This mod contains JavaScript program.
70 | dialog.mods.hostMod = This mod will work on the server.
71 | dialog.mods.deprecated = This mod adapt game version was deprecated.\n[lightgray]missing "minGameVersion:{0}".
72 | dialog.mods.unsupported = Unsupported game version, your game was deprecated.
73 | dialog.mods.libMissing = Some dependence of this mod was missing.
74 | dialog.mods.libIncomplete = Some dependence of this mod was load failed.
75 | dialog.mods.libCircleDepending = There is some circular dependence in this mod dependence.
76 | dialog.mods.error = An error occurred with this mod, please report to the mod developer.
77 | dialog.mods.blackListed = This mod was blocklisted.
78 | dialog.mods.description = Description
79 | dialog.mods.rawText = Raw Text
80 | dialog.mods.contents = Mod Contents
81 | dialog.mods.shouldRelaunch = Should relaunch game
82 | dialog.mods.relaunch = Should relaunch game to apply modifies.
83 | dialog.mods.confirmDeleteHe = Delete Helium mod must relaunch game now!
84 | dialog.mods.deleteMod = Delete Mod
85 | dialog.mods.updateMod = Update Mod
86 | dialog.mods.downloadMod = Download Mod
87 | dialog.mods.importMod = Import Mod
88 | dialog.mods.otherHandle = Other Handles
89 | dialog.mods.reinstall = (Reinstall)
90 | dialog.mods.inputGithubLink = Input github repository link:
91 | dialog.mods.parsing = Parsing Link
92 | dialog.mods.parseFailed = Parse failed, check link
93 | dialog.mods.downloadComplete = Download Complete!
94 | dialog.mods.downloading = Downloading {0}
95 | dialog.mods.noLink = No Github link
96 | dialog.mods.exportLink = Export mod link
97 | dialog.mods.githubLink = The Github link of this mod\uFF1A
98 | dialog.mods.noGithubRepo = This mod was not open sourced on github
99 | dialog.mods.noDownloadLink = Download link was not found.
100 | dialog.mods.installed = This mod has been installed
101 | dialog.mods.newVersion = New version\uFF01
102 | dialog.mods.favorites = Favorites
103 | dialog.mods.noFavorites = No favorite mod yet
104 | dialog.mods.mods = Mod List
105 | dialog.mods.openFolderFailed = Cannot Open Folder
106 | dialog.mods.cantOpenOnAndroid = The file path cannot be opened on an Android device\nYou can copy the following path to open it in the file manager:
107 |
108 | tools.tip.ctrlEntityInfo = Select entity and show details
109 | tools.tip.configEntityInfo = Entity info display settings
110 |
111 | infos.relaunchEnsure = Some configure change must be restart game to take effect
112 | infos.confirmResetConfig = Are you sure to relaunch game?
113 | infos.enabledTeams = Enabled Teams
114 | infos.entityDetails = Details
115 | infos.entityRange = Range
116 | infos.healthDisplay = Health
117 | infos.statusDisplay = Status
118 | infos.enableAll = Enable All
119 | infos.disableAll = Disable All
120 | infos.allSetting = All Settings
121 | infos.copied = Link has been copied to clipboard.
122 | infos.wip = WIP
123 | infos.notImplementYet = Not Implement Yet
124 | infos.exception = Exception!
125 | infos.error = Error!
126 |
127 | misc.later = Later relaunch
128 | misc.exitGame = Exit game
129 | misc.recDefault = Restore default
130 | misc.open = Open
131 | misc.close = Close
132 | misc.copy = Copy
133 | misc.sequence = Forward Sort
134 | misc.reverse = Reverse Sort
135 | misc.download = Download
136 | misc.complete = Complete
137 | misc.save = Save
138 |
--------------------------------------------------------------------------------
/assets/bundles/bundle_id_ID.properties:
--------------------------------------------------------------------------------
1 | he.mod.version = beta-0.6
2 | he.mod.updateDate = 7 Mei 2025
3 |
4 | settings.helium = Konfigurasi Helium
5 | settings.category.basic = Pengaturan Dasar
6 | settings.category.keyBind = Pengaturan Tombol
7 | settings.category.debug = Pengaturan Debug
8 |
9 | settings.basic.backBlur = Latar Belakang Buram
10 | settings.item.enableBlur = Nyalakan Latar Belakang Buram
11 | settings.item.blurScl = Tingkat keburaman
12 | settings.item.blurSpace = Intensitas keburaman
13 |
14 | settings.basic.entityInfo = Informasi Entitas Dalam Permainan
15 | settings.item.enableEntityInfoDisplay = Nyalakan info entitas
16 | settings.item.enableHealthBarDisplay = Nyalakan bar darah
17 | settings.item.enableUnitStatusDisplay = Nyalakan penampil status unit
18 | settings.item.enableRangeDisplay = Nyalakan penampil jarak entitas
19 | settings.item.showAttackRange = Tampilkan jarak serangan
20 | settings.item.showHealRange = Tampilkan jarak penyembuhan
21 | settings.item.showOverdriveRange = Tampilkan jarak pemercepat
22 | settings.item.entityInfoScale = Info entitas menunjukan skala
23 | settings.item.entityInfoAlpha = Info entitas menunjukan alfa(opasitas)
24 |
25 | settings.basic.placement = Panel Penempatan
26 | settings.item.enableBetterPlacement = Nyalakan panel penempatan yang lebih baik
27 |
28 | settings.basic.modsDialog = Manajer Mod
29 | settings.item.enableBetterModsDialog = Nyalakan dialog mod yang lebih baik
30 |
31 | settings.debug.logging = Informasi Log
32 | settings.item.loadingInfo = Keluaran info memuat
33 |
34 | settings.keyBind.placement = Panel Penempatan
35 | settings.item.placementFoldHotKey = Lipat/Buka lipat panel penempatan
36 | settings.item.switchFastPageHotKey = Tukar lembar inventaris
37 |
38 | settings.keyBind.entityInfo = Informasi Entitas Dalam Permainan
39 | settings.item.entityInfoHotKey = Pengaturan kunci info entitas
40 |
41 | config.showAttackRange = Tmplkn\njarak\nsrangn
42 | config.showHealRange = Tmplkn jrk pnymbhan
43 | config.showOverdriveRange = Tmplkn jrk pmrcpat
44 |
45 | dialog.mods.enabled = Mod Diaktifkan
46 | dialog.mods.disabled = Mod Dinonaktifkan
47 | dialog.mods.menu = Menu
48 | dialog.mods.upgradeAll = Semua Pembaruan
49 | dialog.mods.checkUpdate = Periksa Pembaruan
50 | dialog.mods.checkFailed = Gagal mendapat
51 | dialog.mods.checkUpdateFailed = Periksa pembaruan gagal
52 | dialog.mods.downloadFailed = Gagal mengunduh
53 | dialog.mods.checkUpdating = Mengeperiksa Pembaruan
54 | dialog.mods.updateValid = Pembaruan tersedia untuk mod ini\nVersi terakhir:{0}.
55 | dialog.mods.updateValidS = Pembaruan yang benar telah ditemukan.
56 | dialog.mods.modStatCorrect = Mod ini telah dimuat dengan tepat.
57 | dialog.mods.modStatError = Mod ini tidak sah.
58 | dialog.mods.isLatest = Saat ini adalah versi terakhir.
59 | dialog.mods.exportPack = Ekspor ModPack (Paket Mod)
60 | dialog.mods.refresh = Muat Ulang
61 | dialog.mods.importFav = Impor Favorit
62 | dialog.mods.exportFav = Ekspor Favorit
63 | dialog.mods.favoritesText = Ekspor teks favorit\uFF1A
64 | dialog.mods.hideInvalid = Sembunyikan mod cacat.
65 | dialog.mods.author = Author: {0}
66 | dialog.mods.version = Versi\uFF1A{0}
67 | dialog.mods.jarMod = Mod ini berisi program Java.
68 | dialog.mods.jsMod = Mod ini berisi program JavaScript.
69 | dialog.mods.hostMod = Mod in akan bekerja di dalam server.
70 | dialog.mods.deprecated = Versi game mod yang disesuaikan telah usang.\n[lightgray]"minGameVersion:{0}" hilang.
71 | dialog.mods.unsupported = Versi game tidak terdukung, permainanmu telah usang.
72 | dialog.mods.libMissing = Beberapa dependensi dari mod ini telah hilang.
73 | dialog.mods.libIncomplete = Beberapa dependensi dari mod ini gagal memuat.
74 | dialog.mods.libCircleDepending = Terdapat beberapa dependensi yang keliru pada dependensi mod ini.
75 | dialog.mods.error = Error terjadi pada mod ini, mohon laporkan ke pengembang mod.
76 | dialog.mods.blackListed = Mod ini telah terdaftar hitamkan.
77 | dialog.mods.description = Deskripsi
78 | dialog.mods.rawText = Teks Mentah
79 | dialog.mods.contents = Konten Mod
80 | dialog.mods.shouldRelaunch = Harus menjalankan ulang permainan
81 | dialog.mods.relaunch = Harus menjalankan ulang permainan untuk menerapkan modifikasi.
82 | dialog.mods.confirmDeleteHe = Harus menjalankan ulang permainan jika Hapus mod Helium sekarang!
83 | dialog.mods.deleteMod = Hapus Mod
84 | dialog.mods.updateMod = Pembarui Mod
85 | dialog.mods.downloadMod = Unduh Mod
86 | dialog.mods.importMod = Impor Mod
87 | dialog.mods.otherHandle = Pemegang Lainnya
88 | dialog.mods.reinstall = (Install Ulang)
89 | dialog.mods.inputGithubLink = Masukan tautan repositori Github:
90 | dialog.mods.parsing = Mengurai Tautan
91 | dialog.mods.parseFailed = Gagal mengurai, periksa tautan
92 | dialog.mods.downloadComplete = Unduh Selesai!
93 | dialog.mods.downloading = Mengunduh {0}
94 | dialog.mods.noLink = Tidak ada tautan Github
95 | dialog.mods.exportLink = Ekspor tautan mod
96 | dialog.mods.githubLink = Tautan Github dari mod ini\uFF1A
97 | dialog.mods.noGithubRepo = Mod ini tidak sumber terbuka di Github
98 | dialog.mods.noDownloadLink = Link unduhan tidak ditemukan.
99 | dialog.mods.installed = Mod ini telah terinstal
100 | dialog.mods.newVersion = Versi terbaru\uFF01
101 | dialog.mods.favorites = Favorit
102 | dialog.mods.noFavorites = Belum ada mod favorit barusan
103 | dialog.mods.mods = Daftar Mod
104 | dialog.mods.openFolderFailed = Tidak dapat membuka folder
105 | dialog.mods.cantOpenOnAndroid = Jalur file tidak dapat dibuka di Android\nKau dapat menyalinkan jalur dan membukanya di penelusur file:
106 |
107 | tools.tip.ctrlEntityInfo = Pilih entitas untuk menampilkan detil
108 | tools.tip.configEntityInfo = Pengaturan tampilan info entitas
109 |
110 | infos.relaunchEnsure = Beberapa perubahan konfigurasi harus diterapkan dengan menjalankan ulang permainan.
111 | infos.confirmResetConfig = Kau yakin untuk menjalankan ulang permainan?
112 | infos.enabledTeams = Tim Dinyalakan
113 | infos.entityDetails = Detil
114 | infos.entityRange = Jarak
115 | infos.healthDisplay = Darah
116 | infos.statusDisplay = Status
117 | infos.enableAll = Aktif\nSemua
118 | infos.disableAll = Nonaktif\nSemua
119 | infos.allSetting = Semua Pengaturan
120 | infos.copied = Tautan telah disalin ke papan klip
121 | infos.wip = WIP
122 | infos.notImplementYet = Belum diimplementasikan
123 | infos.exception = Kesalahan!
124 | infos.error = Error!
125 |
126 | misc.later = Luncurkan ulang nanti
127 | misc.exitGame = Keluar permainan
128 | misc.recDefault = Atur Ulang ke Bawaan
129 | misc.open = Buka
130 | misc.close = Tutup
131 | misc.copy = Salin
132 | misc.sequence = Urut Kedepan
133 | misc.reverse = Urut Terbalik
134 | misc.download = Unduh
135 | misc.complete = Selesai
136 | misc.save = Simpan
137 |
--------------------------------------------------------------------------------
/assets/bundles/bundle_zh_CN.properties:
--------------------------------------------------------------------------------
1 | he.mod.version = beta-0.6
2 | he.mod.updateDate = 2025\u5E746\u67085\u65E5
3 |
4 | settings.helium = \u6C26\u914D\u7F6E
5 | settings.category.basic = \u57FA\u7840\u8BBE\u7F6E
6 | settings.category.keyBind = \u952E\u4F4D\u7ED1\u5B9A
7 | settings.category.debug = \u8C03\u8BD5\u8BBE\u7F6E
8 |
9 | settings.basic.backBlur = \u80CC\u666F\u6A21\u7CCA
10 | settings.item.enableBlur = \u542F\u7528\u80CC\u666F\u6A21\u7CCA
11 | settings.item.blurScl = \u6A21\u7CCA\u7EA7\u522B
12 | settings.item.blurSpace = \u6A21\u7CCA\u5F3A\u5EA6
13 |
14 | settings.basic.entityInfo = \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668
15 | settings.item.enableEntityInfoDisplay = \u542F\u7528\u5B9E\u4F53\u4FE1\u606F\u663E\u793A
16 | settings.item.enableHealthBarDisplay = \u542F\u7528\u751F\u547D\u503C\u663E\u793A\u9762\u677F
17 | settings.item.enableUnitStatusDisplay = \u542F\u7528\u5355\u4F4D\u72B6\u6001\u663E\u793A
18 | settings.item.enableRangeDisplay = \u542F\u7528\u8303\u56F4\u663E\u793A
19 | settings.item.showAttackRange = \u663E\u793A\u653B\u51FB\u8303\u56F4
20 | settings.item.showHealRange = \u663E\u793A\u4FEE\u590D\u8303\u56F4
21 | settings.item.showOverdriveRange = \u663E\u793A\u8D85\u901F\u6295\u5F71\u8303\u56F4
22 | settings.item.entityInfoScale = \u4FE1\u606F\u663E\u793A\u7F29\u653E
23 | settings.item.entityInfoAlpha = \u4FE1\u606F\u6307\u793A\u5668\u900F\u660E\u5EA6
24 |
25 | settings.basic.placement = \u653E\u7F6E\u9762\u677F
26 | settings.item.enableBetterPlacement = \u542F\u7528\u66F4\u597D\u7684\u653E\u7F6E\u9762\u677F
27 |
28 | settings.basic.modsDialog = \u6A21\u7EC4\u7BA1\u7406\u5668
29 | settings.item.enableBetterModsDialog = \u542F\u7528\u66F4\u597D\u7684\u6A21\u7EC4\u7BA1\u7406\u5668
30 |
31 | settings.debug.logging = \u65E5\u5FD7\u4FE1\u606F
32 | settings.item.loadingInfo = \u8F93\u51FA\u52A0\u8F7D\u4FE1\u606F
33 |
34 | settings.keyBind.placement = \u653E\u7F6E\u9762\u677F
35 | settings.item.placementFoldHotKey = \u6298\u53E0/\u5C55\u5F00\u653E\u7F6E\u9762\u677F
36 | settings.item.switchFastPageHotKey = \u5FEB\u901F\u7269\u54C1\u680F\u7FFB\u9875
37 |
38 | settings.keyBind.entityInfo = \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668
39 | settings.item.entityInfoHotKey = \u4FE1\u606F\u663E\u793A\u63A7\u5236\u952E
40 |
41 | config.showAttackRange = \u663E\u793A\u653B\u51FB\u8303\u56F4
42 | config.showHealRange = \u663E\u793A\u4FEE\u590D\u8303\u56F4
43 | config.showOverdriveRange = \u663E\u793A\u8D85\u901F\u6295\u5F71\u8303\u56F4
44 |
45 | dialog.mods.enabled = \u5DF2\u542F\u7528
46 | dialog.mods.disabled = \u5DF2\u7981\u7528
47 | dialog.mods.menu = \u83DC\u5355
48 | dialog.mods.upgradeAll = \u5168\u90E8\u66F4\u65B0
49 | dialog.mods.checkUpdate = \u68C0\u67E5\u66F4\u65B0
50 | dialog.mods.checkFailed = \u83B7\u53D6\u5931\u8D25
51 | dialog.mods.checkUpdateFailed = \u68C0\u67E5\u66F4\u65B0\u5931\u8D25
52 | dialog.mods.downloadFailed = \u4E0B\u8F7D\u5931\u8D25
53 | dialog.mods.checkUpdating = \u6B63\u5728\u68C0\u67E5\u66F4\u65B0
54 | dialog.mods.updateValid = \u6B64mod\u6709\u53EF\u7528\u7684\u66F4\u65B0\n\u6700\u65B0\u7248\u672C\uFF1A{0}
55 | dialog.mods.updateValidS = \u53D1\u73B0\u53EF\u7528\u7684\u66F4\u65B0
56 | dialog.mods.modStatCorrect = mod\u5DF2\u6B63\u5E38\u88C5\u8F7D
57 | dialog.mods.modStatError = \u6B64mod\u4E0D\u53EF\u7528
58 | dialog.mods.isLatest = \u5DF2\u662F\u6700\u65B0\u7248\u672C
59 | dialog.mods.exportPack = \u5BFC\u51FA\u6574\u5408\u5305
60 | dialog.mods.refresh = \u5237\u65B0
61 | dialog.mods.importFav = \u5BFC\u5165\u6536\u85CF\u5939
62 | dialog.mods.inputFavText = \u5728\u4E0B\u65B9\u8F93\u5165\u6536\u85CF\u5939\u6587\u672C\uFF1A
63 | dialog.mods.exportFav = \u5BFC\u51FA\u6536\u85CF\u5939
64 | dialog.mods.favoritesText = \u5BFC\u51FA\u6536\u85CF\u5939\u6587\u672C\uFF1A
65 | dialog.mods.hideInvalid = \u9690\u85CF\u4E0D\u53EF\u7528\u7684mod
66 | dialog.mods.author = \u4F5C\u8005\uFF1A{0}
67 | dialog.mods.version = \u7248\u672C\uFF1A{0}
68 | dialog.mods.jarMod = \u6B64mod\u5305\u542Bjava\u7A0B\u5E8F
69 | dialog.mods.jsMod = \u6B64mod\u5305\u542BJavaScript\u7A0B\u5E8F
70 | dialog.mods.hostMod = \u6B64mod\u4F1A\u5728\u670D\u52A1\u5668\u4E3B\u673A\u4E0A\u5DE5\u4F5C
71 | dialog.mods.deprecated = \u6B64mod\u9002\u914D\u7684\u6E38\u620F\u7248\u672C\u5DF2\u8FC7\u65F6\n[lightgray]\u7F3A\u5C11"minGameVersion:{0}"
72 | dialog.mods.unsupported = \u4E0D\u517C\u5BB9\u8FC7\u65F6\u7684\u6E38\u620F\u7248\u672C\u7248\u672C\uFF0C\u8BF7\u66F4\u65B0\u4F60\u7684\u6E38\u620F
73 | dialog.mods.libMissing = \u7F3A\u5C11\u6B64mod\u7684\u4F9D\u8D56mod
74 | dialog.mods.libIncomplete = \u6B64mod\u7684\u4F9D\u8D56\u9879\u5B58\u5728\u9519\u8BEF
75 | dialog.mods.libCircleDepending = \u6B64mod\u5B58\u5728\u4F9D\u8D56\u5FAA\u73AF\uFF0C\u8BF7\u62A5\u544Amod\u5F00\u53D1\u8005
76 | dialog.mods.error = \u6B64mod\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u62A5\u544Amod\u5F00\u53D1\u8005
77 | dialog.mods.blackListed = \u6B64mod\u5DF2\u88AB\u5217\u5165\u9ED1\u540D\u5355
78 | dialog.mods.description = mod\u63CF\u8FF0
79 | dialog.mods.rawText = \u539F\u59CB\u6587\u672C
80 | dialog.mods.contents = mod\u5185\u5BB9
81 | dialog.mods.shouldRelaunch = \u9700\u8981\u91CD\u542F
82 | dialog.mods.relaunch = \u9700\u8981\u91CD\u542F\u6E38\u620F\u624D\u80FD\u5E94\u7528\u8FD9\u4E9B\u53D8\u66F4
83 | dialog.mods.confirmDeleteHe = \u5220\u9664\u6C26mod\u9700\u8981\u7ACB\u5373\u91CD\u542F\u6E38\u620F\uFF0C\u786E\u5B9A\u5417\uFF1F
84 | dialog.mods.deleteMod = \u5220\u9664mod
85 | dialog.mods.updateMod = \u66F4\u65B0mod
86 | dialog.mods.downloadMod = \u4E0B\u8F7Dmod
87 | dialog.mods.importMod = \u5BFC\u5165mod
88 | dialog.mods.otherHandle = \u5176\u4ED6\u64CD\u4F5C
89 | dialog.mods.reinstall = \uFF08\u91CD\u65B0\u5B89\u88C5\uFF09
90 | dialog.mods.inputGithubLink = \uF308 \u8F93\u5165mod\u7684Github\u4ED3\u5E93\u94FE\u63A5
91 | dialog.mods.parsing = \u6B63\u5728\u89E3\u6790\u94FE\u63A5
92 | dialog.mods.parseFailed = \u89E3\u6790\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u6B63\u786E
93 | dialog.mods.downloadComplete = \u4E0B\u8F7D\u5B8C\u6210
94 | dialog.mods.downloading = \u6B63\u5728\u4E0B\u8F7D {0}
95 | dialog.mods.noLink = \u672A\u627E\u5230\u94FE\u63A5
96 | dialog.mods.exportLink = \u5BFC\u51FA\u94FE\u63A5
97 | dialog.mods.githubLink = \u6B64mod\u7684github\u94FE\u63A5\uFF1A
98 | dialog.mods.noGithubRepo = \u6B64mod\u6CA1\u6709\u5F00\u6E90\u5230github
99 | dialog.mods.noDownloadLink = \u6CA1\u6709\u627E\u5230\u4E0B\u8F7D\u94FE\u63A5
100 | dialog.mods.installed = \u6B64mod\u5DF2\u5B89\u88C5
101 | dialog.mods.newVersion = \u65B0\u7248\u672C\uFF01
102 | dialog.mods.favorites = \u6536\u85CF\u5939
103 | dialog.mods.noFavorites = \u6CA1\u6709\u6536\u85CF\u4EFB\u4F55mod
104 | dialog.mods.mods = mod\u5217\u8868
105 | dialog.mods.openFolderFailed = \u65E0\u6CD5\u6253\u5F00\u76EE\u5F55
106 | dialog.mods.cantOpenOnAndroid = \u5728Android\u8BBE\u5907\u4E0A\u65E0\u6CD5\u6253\u5F00\u6587\u4EF6\u8DEF\u5F84\n\u4F60\u53EF\u4EE5\u590D\u5236\u5982\u4E0B\u8DEF\u5F84\u624B\u52A8\u5728\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u6253\u5F00\uFF1A
107 |
108 | tools.tip.ctrlEntityInfo = \u9009\u62E9\u5E76\u663E\u793A\u5B9E\u4F53\u8BE6\u60C5
109 | tools.tip.configEntityInfo = \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668\u8BBE\u7F6E
110 |
111 | infos.relaunchEnsure = \u4E00\u4E9B\u914D\u7F6E\u9879\u7684\u53D8\u66F4\u9700\u8981\u91CD\u542F\u751F\u6548
112 | infos.confirmResetConfig = \u786E\u5B9A\u8981\u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E\u5417\uFF1F
113 | infos.enabledTeams = \u542F\u7528\u7684\u961F\u4F0D
114 | infos.entityDetails = \u8BE6\u7EC6\u4FE1\u606F
115 | infos.entityRange = \u8303\u56F4\u663E\u793A\u5668
116 | infos.healthDisplay = \u751F\u547D\u663E\u793A\u5668
117 | infos.statusDisplay = \u72B6\u6001\u6307\u793A\u5668
118 | infos.enableAll = \u542F\u7528\u5168\u90E8
119 | infos.disableAll = \u7981\u7528\u5168\u90E8
120 | infos.allSetting = \u5168\u90E8\u8BBE\u7F6E
121 | infos.copied = \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F
122 | infos.wip = WIP
123 | infos.notImplementYet = \u6682\u672A\u5B9E\u73B0
124 | infos.exception = \u53D1\u751F\u5F02\u5E38\uFF01
125 | infos.error = \u53D1\u751F\u9519\u8BEF\uFF01
126 |
127 | misc.later = \u7A0D\u540E\u91CD\u542F
128 | misc.exitGame = \u9000\u51FA\u6E38\u620F
129 | misc.recDefault = \u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E
130 | misc.open = \u6253\u5F00
131 | misc.close = \u5173\u95ED
132 | misc.copy = \u590D\u5236
133 | misc.sequence = \u987A\u5E8F
134 | misc.reverse = \u9006\u5E8F
135 | misc.download = \u4E0B\u8F7D
136 | misc.complete = \u5B8C\u6210
137 | misc.save = \u4FDD\u5B58
138 |
--------------------------------------------------------------------------------
/assets/bundles/bundle_zh_TW.properties:
--------------------------------------------------------------------------------
1 | he.mod.version = beta-0.6
2 | he.mod.updateDate = 2025\u5E746\u67085\u65E5
3 |
4 | settings.helium = (\u5F85\u7FFB\u8B6F) \u6C26\u914D\u7F6E
5 | settings.category.basic = (\u5F85\u7FFB\u8B6F) \u57FA\u7840\u8BBE\u7F6E
6 | settings.category.keyBind = (\u5F85\u7FFB\u8B6F) \u952E\u4F4D\u7ED1\u5B9A
7 | settings.category.debug = (\u5F85\u7FFB\u8B6F) \u8C03\u8BD5\u8BBE\u7F6E
8 |
9 | settings.basic.backBlur = (\u5F85\u7FFB\u8B6F) \u80CC\u666F\u6A21\u7CCA
10 | settings.item.enableBlur = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u80CC\u666F\u6A21\u7CCA
11 | settings.item.blurScl = (\u5F85\u7FFB\u8B6F) \u6A21\u7CCA\u7EA7\u522B
12 | settings.item.blurSpace = (\u5F85\u7FFB\u8B6F) \u6A21\u7CCA\u5F3A\u5EA6
13 |
14 | settings.basic.entityInfo = (\u5F85\u7FFB\u8B6F) \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668
15 | settings.item.enableEntityInfoDisplay = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u5B9E\u4F53\u4FE1\u606F\u663E\u793A
16 | settings.item.enableHealthBarDisplay = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u751F\u547D\u503C\u663E\u793A\u9762\u677F
17 | settings.item.enableUnitStatusDisplay = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u5355\u4F4D\u72B6\u6001\u663E\u793A
18 | settings.item.enableRangeDisplay = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u8303\u56F4\u663E\u793A
19 | settings.item.showAttackRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u653B\u51FB\u8303\u56F4
20 | settings.item.showHealRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u4FEE\u590D\u8303\u56F4
21 | settings.item.showOverdriveRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u8D85\u901F\u6295\u5F71\u8303\u56F4
22 | settings.item.entityInfoScale = (\u5F85\u7FFB\u8B6F) \u4FE1\u606F\u663E\u793A\u7F29\u653E
23 | settings.item.entityInfoAlpha = (\u5F85\u7FFB\u8B6F) \u4FE1\u606F\u6307\u793A\u5668\u900F\u660E\u5EA6
24 |
25 | settings.basic.placement = (\u5F85\u7FFB\u8B6F) \u653E\u7F6E\u9762\u677F
26 | settings.item.enableBetterPlacement = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u66F4\u597D\u7684\u653E\u7F6E\u9762\u677F
27 |
28 | settings.basic.modsDialog = (\u5F85\u7FFB\u8B6F) \u6A21\u7EC4\u7BA1\u7406\u5668
29 | settings.item.enableBetterModsDialog = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u66F4\u597D\u7684\u6A21\u7EC4\u7BA1\u7406\u5668
30 |
31 | settings.debug.logging = (\u5F85\u7FFB\u8B6F) \u65E5\u5FD7\u4FE1\u606F
32 | settings.item.loadingInfo = (\u5F85\u7FFB\u8B6F) \u8F93\u51FA\u52A0\u8F7D\u4FE1\u606F
33 |
34 | settings.keyBind.placement = (\u5F85\u7FFB\u8B6F) \u653E\u7F6E\u9762\u677F
35 | settings.item.placementFoldHotKey = (\u5F85\u7FFB\u8B6F) \u6298\u53E0/\u5C55\u5F00\u653E\u7F6E\u9762\u677F
36 | settings.item.switchFastPageHotKey = (\u5F85\u7FFB\u8B6F) \u5FEB\u901F\u7269\u54C1\u680F\u7FFB\u9875
37 |
38 | settings.keyBind.entityInfo = (\u5F85\u7FFB\u8B6F) \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668
39 | settings.item.entityInfoHotKey = (\u5F85\u7FFB\u8B6F) \u4FE1\u606F\u663E\u793A\u63A7\u5236\u952E
40 |
41 | config.showAttackRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u653B\u51FB\u8303\u56F4
42 | config.showHealRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u4FEE\u590D\u8303\u56F4
43 | config.showOverdriveRange = (\u5F85\u7FFB\u8B6F) \u663E\u793A\u8D85\u901F\u6295\u5F71\u8303\u56F4
44 |
45 | dialog.mods.enabled = (\u5F85\u7FFB\u8B6F) \u5DF2\u542F\u7528
46 | dialog.mods.disabled = (\u5F85\u7FFB\u8B6F) \u5DF2\u7981\u7528
47 | dialog.mods.menu = (\u5F85\u7FFB\u8B6F) \u83DC\u5355
48 | dialog.mods.upgradeAll = (\u5F85\u7FFB\u8B6F) \u5168\u90E8\u66F4\u65B0
49 | dialog.mods.checkUpdate = (\u5F85\u7FFB\u8B6F) \u68C0\u67E5\u66F4\u65B0
50 | dialog.mods.checkFailed = (\u5F85\u7FFB\u8B6F) \u83B7\u53D6\u5931\u8D25
51 | dialog.mods.checkUpdateFailed = (\u5F85\u7FFB\u8B6F) \u68C0\u67E5\u66F4\u65B0\u5931\u8D25
52 | dialog.mods.downloadFailed = (\u5F85\u7FFB\u8B6F) \u4E0B\u8F7D\u5931\u8D25
53 | dialog.mods.checkUpdating = (\u5F85\u7FFB\u8B6F) \u6B63\u5728\u68C0\u67E5\u66F4\u65B0
54 | dialog.mods.updateValid = (\u5F85\u7FFB\u8B6F) \u6B64mod\u6709\u53EF\u7528\u7684\u66F4\u65B0\n\u6700\u65B0\u7248\u672C\uFF1A{0}
55 | dialog.mods.updateValidS = (\u5F85\u7FFB\u8B6F) \u53D1\u73B0\u53EF\u7528\u7684\u66F4\u65B0
56 | dialog.mods.modStatCorrect = (\u5F85\u7FFB\u8B6F) mod\u5DF2\u6B63\u5E38\u88C5\u8F7D
57 | dialog.mods.modStatError = (\u5F85\u7FFB\u8B6F) \u6B64mod\u4E0D\u53EF\u7528
58 | dialog.mods.isLatest = (\u5F85\u7FFB\u8B6F) \u5DF2\u662F\u6700\u65B0\u7248\u672C
59 | dialog.mods.exportPack = (\u5F85\u7FFB\u8B6F) \u5BFC\u51FA\u6574\u5408\u5305
60 | dialog.mods.refresh = (\u5F85\u7FFB\u8B6F) \u5237\u65B0
61 | dialog.mods.importFav = (\u5F85\u7FFB\u8B6F) \u5BFC\u5165\u6536\u85CF\u5939
62 | dialog.mods.inputFavText = (\u5F85\u7FFB\u8B6F) \u5728\u4E0B\u65B9\u8F93\u5165\u6536\u85CF\u5939\u6587\u672C\uFF1A
63 | dialog.mods.exportFav = (\u5F85\u7FFB\u8B6F) \u5BFC\u51FA\u6536\u85CF\u5939
64 | dialog.mods.favoritesText = (\u5F85\u7FFB\u8B6F) \u5BFC\u51FA\u6536\u85CF\u5939\u6587\u672C\uFF1A
65 | dialog.mods.hideInvalid = (\u5F85\u7FFB\u8B6F) \u9690\u85CF\u4E0D\u53EF\u7528\u7684mod
66 | dialog.mods.author = (\u5F85\u7FFB\u8B6F) \u4F5C\u8005\uFF1A{0}
67 | dialog.mods.version = (\u5F85\u7FFB\u8B6F) \u7248\u672C\uFF1A{0}
68 | dialog.mods.jarMod = (\u5F85\u7FFB\u8B6F) \u6B64mod\u5305\u542Bjava\u7A0B\u5E8F
69 | dialog.mods.jsMod = (\u5F85\u7FFB\u8B6F) \u6B64mod\u5305\u542BJavaScript\u7A0B\u5E8F
70 | dialog.mods.hostMod = (\u5F85\u7FFB\u8B6F) \u6B64mod\u4F1A\u5728\u670D\u52A1\u5668\u4E3B\u673A\u4E0A\u5DE5\u4F5C
71 | dialog.mods.deprecated = (\u5F85\u7FFB\u8B6F) \u6B64mod\u9002\u914D\u7684\u6E38\u620F\u7248\u672C\u5DF2\u8FC7\u65F6\n[lightgray]\u7F3A\u5C11"minGameVersion:{0}"
72 | dialog.mods.unsupported = (\u5F85\u7FFB\u8B6F) \u4E0D\u517C\u5BB9\u8FC7\u65F6\u7684\u6E38\u620F\u7248\u672C\u7248\u672C\uFF0C\u8BF7\u66F4\u65B0\u4F60\u7684\u6E38\u620F
73 | dialog.mods.libMissing = (\u5F85\u7FFB\u8B6F) \u7F3A\u5C11\u6B64mod\u7684\u4F9D\u8D56mod
74 | dialog.mods.libIncomplete = (\u5F85\u7FFB\u8B6F) \u6B64mod\u7684\u4F9D\u8D56\u9879\u5B58\u5728\u9519\u8BEF
75 | dialog.mods.libCircleDepending = (\u5F85\u7FFB\u8B6F) \u6B64mod\u5B58\u5728\u4F9D\u8D56\u5FAA\u73AF\uFF0C\u8BF7\u62A5\u544Amod\u5F00\u53D1\u8005
76 | dialog.mods.error = (\u5F85\u7FFB\u8B6F) \u6B64mod\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u62A5\u544Amod\u5F00\u53D1\u8005
77 | dialog.mods.blackListed = (\u5F85\u7FFB\u8B6F) \u6B64mod\u5DF2\u88AB\u5217\u5165\u9ED1\u540D\u5355
78 | dialog.mods.description = (\u5F85\u7FFB\u8B6F) mod\u63CF\u8FF0
79 | dialog.mods.rawText = (\u5F85\u7FFB\u8B6F) \u539F\u59CB\u6587\u672C
80 | dialog.mods.contents = (\u5F85\u7FFB\u8B6F) mod\u5185\u5BB9
81 | dialog.mods.shouldRelaunch = (\u5F85\u7FFB\u8B6F) \u9700\u8981\u91CD\u542F
82 | dialog.mods.relaunch = (\u5F85\u7FFB\u8B6F) \u9700\u8981\u91CD\u542F\u6E38\u620F\u624D\u80FD\u5E94\u7528\u8FD9\u4E9B\u53D8\u66F4
83 | dialog.mods.confirmDeleteHe = (\u5F85\u7FFB\u8B6F) \u5220\u9664\u6C26mod\u9700\u8981\u7ACB\u5373\u91CD\u542F\u6E38\u620F\uFF0C\u786E\u5B9A\u5417\uFF1F
84 | dialog.mods.deleteMod = (\u5F85\u7FFB\u8B6F) \u5220\u9664mod
85 | dialog.mods.updateMod = (\u5F85\u7FFB\u8B6F) \u66F4\u65B0mod
86 | dialog.mods.downloadMod = (\u5F85\u7FFB\u8B6F) \u4E0B\u8F7Dmod
87 | dialog.mods.importMod = (\u5F85\u7FFB\u8B6F) \u5BFC\u5165mod
88 | dialog.mods.otherHandle = (\u5F85\u7FFB\u8B6F) \u5176\u4ED6\u64CD\u4F5C
89 | dialog.mods.reinstall = (\u5F85\u7FFB\u8B6F) \uFF08\u91CD\u65B0\u5B89\u88C5\uFF09
90 | dialog.mods.inputGithubLink = (\u5F85\u7FFB\u8B6F) \uF308 \u8F93\u5165mod\u7684Github\u4ED3\u5E93\u94FE\u63A5
91 | dialog.mods.parsing = (\u5F85\u7FFB\u8B6F) \u6B63\u5728\u89E3\u6790\u94FE\u63A5
92 | dialog.mods.parseFailed = (\u5F85\u7FFB\u8B6F) \u89E3\u6790\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u6B63\u786E
93 | dialog.mods.downloadComplete = (\u5F85\u7FFB\u8B6F) \u4E0B\u8F7D\u5B8C\u6210
94 | dialog.mods.downloading = (\u5F85\u7FFB\u8B6F) \u6B63\u5728\u4E0B\u8F7D {0}
95 | dialog.mods.noLink = (\u5F85\u7FFB\u8B6F) \u672A\u627E\u5230\u94FE\u63A5
96 | dialog.mods.exportLink = (\u5F85\u7FFB\u8B6F) \u5BFC\u51FA\u94FE\u63A5
97 | dialog.mods.githubLink = (\u5F85\u7FFB\u8B6F) \u6B64mod\u7684github\u94FE\u63A5\uFF1A
98 | dialog.mods.noGithubRepo = (\u5F85\u7FFB\u8B6F) \u6B64mod\u6CA1\u6709\u5F00\u6E90\u5230github
99 | dialog.mods.noDownloadLink = (\u5F85\u7FFB\u8B6F) \u6CA1\u6709\u627E\u5230\u4E0B\u8F7D\u94FE\u63A5
100 | dialog.mods.installed = (\u5F85\u7FFB\u8B6F) \u6B64mod\u5DF2\u5B89\u88C5
101 | dialog.mods.newVersion = (\u5F85\u7FFB\u8B6F) \u65B0\u7248\u672C\uFF01
102 | dialog.mods.favorites = (\u5F85\u7FFB\u8B6F) \u6536\u85CF\u5939
103 | dialog.mods.noFavorites = (\u5F85\u7FFB\u8B6F) \u6CA1\u6709\u6536\u85CF\u4EFB\u4F55mod
104 | dialog.mods.mods = (\u5F85\u7FFB\u8B6F) mod\u5217\u8868
105 | dialog.mods.openFolderFailed = (\u5F85\u7FFB\u8B6F) \u65E0\u6CD5\u6253\u5F00\u76EE\u5F55
106 | dialog.mods.cantOpenOnAndroid = (\u5F85\u7FFB\u8B6F) \u5728Android\u8BBE\u5907\u4E0A\u65E0\u6CD5\u6253\u5F00\u6587\u4EF6\u8DEF\u5F84\n\u4F60\u53EF\u4EE5\u590D\u5236\u5982\u4E0B\u8DEF\u5F84\u624B\u52A8\u5728\u6587\u4EF6\u7BA1\u7406\u5668\u4E2D\u6253\u5F00\uFF1A
107 |
108 | tools.tip.ctrlEntityInfo = (\u5F85\u7FFB\u8B6F) \u9009\u62E9\u5E76\u663E\u793A\u5B9E\u4F53\u8BE6\u60C5
109 | tools.tip.configEntityInfo = (\u5F85\u7FFB\u8B6F) \u5B9E\u4F53\u4FE1\u606F\u663E\u793A\u5668\u8BBE\u7F6E
110 |
111 | infos.relaunchEnsure = (\u5F85\u7FFB\u8B6F) \u4E00\u4E9B\u914D\u7F6E\u9879\u7684\u53D8\u66F4\u9700\u8981\u91CD\u542F\u751F\u6548
112 | infos.confirmResetConfig = (\u5F85\u7FFB\u8B6F) \u786E\u5B9A\u8981\u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E\u5417\uFF1F
113 | infos.enabledTeams = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u7684\u961F\u4F0D
114 | infos.entityDetails = (\u5F85\u7FFB\u8B6F) \u8BE6\u7EC6\u4FE1\u606F
115 | infos.entityRange = (\u5F85\u7FFB\u8B6F) \u8303\u56F4\u663E\u793A\u5668
116 | infos.healthDisplay = (\u5F85\u7FFB\u8B6F) \u751F\u547D\u663E\u793A\u5668
117 | infos.statusDisplay = (\u5F85\u7FFB\u8B6F) \u72B6\u6001\u6307\u793A\u5668
118 | infos.enableAll = (\u5F85\u7FFB\u8B6F) \u542F\u7528\u5168\u90E8
119 | infos.disableAll = (\u5F85\u7FFB\u8B6F) \u7981\u7528\u5168\u90E8
120 | infos.allSetting = (\u5F85\u7FFB\u8B6F) \u5168\u90E8\u8BBE\u7F6E
121 | infos.copied = (\u5F85\u7FFB\u8B6F) \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F
122 | infos.wip = (\u5F85\u7FFB\u8B6F) WIP
123 | infos.notImplementYet = (\u5F85\u7FFB\u8B6F) \u6682\u672A\u5B9E\u73B0
124 | infos.exception = (\u5F85\u7FFB\u8B6F) \u53D1\u751F\u5F02\u5E38\uFF01
125 | infos.error = (\u5F85\u7FFB\u8B6F) \u53D1\u751F\u9519\u8BEF\uFF01
126 |
127 | misc.later = (\u5F85\u7FFB\u8B6F) \u7A0D\u540E\u91CD\u542F
128 | misc.exitGame = (\u5F85\u7FFB\u8B6F) \u9000\u51FA\u6E38\u620F
129 | misc.recDefault = (\u5F85\u7FFB\u8B6F) \u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E
130 | misc.open = (\u5F85\u7FFB\u8B6F) \u6253\u5F00
131 | misc.close = (\u5F85\u7FFB\u8B6F) \u5173\u95ED
132 | misc.copy = (\u5F85\u7FFB\u8B6F) \u590D\u5236
133 | misc.sequence = (\u5F85\u7FFB\u8B6F) \u987A\u5E8F
134 | misc.reverse = (\u5F85\u7FFB\u8B6F) \u9006\u5E8F
135 | misc.download = (\u5F85\u7FFB\u8B6F) \u4E0B\u8F7D
136 | misc.complete = (\u5F85\u7FFB\u8B6F) \u5B8C\u6210
137 | misc.save = (\u5F85\u7FFB\u8B6F) \u4FDD\u5B58
138 |
--------------------------------------------------------------------------------
/assets/config/mod_config.hjson:
--------------------------------------------------------------------------------
1 | {
2 | "configVersion": 3,
3 |
4 | //=====Basic/基础设置=====//
5 |
6 | //启用UI模糊视效
7 | "enableBlur": true,
8 | //模糊级别
9 | "blurScl": 4,
10 | //模糊强度
11 | "blurSpace": 1.25,
12 |
13 | //启用实体信息显示器
14 | "enableEntityInfoDisplay": true,
15 | //信息显示缩放
16 | "entityInfoScale": 1.0,
17 | //信息指示器透明度
18 | "entityInfoAlpha": 1.0,
19 | //启用生命值面板
20 | "enableHealthBarDisplay": true,
21 | //启用状态指示器
22 | "enableUnitStatusDisplay": true,
23 | //启用范围指示器
24 | "enableRangeDisplay": true,
25 | //显示实体攻击范围
26 | "showAttackRange": true,
27 | //显示修复范围
28 | "showHealRange": true,
29 | //显示超速投影作用范围
30 | "showOverdriveRange": true,
31 |
32 | //启用更好的放置面板
33 | "enableBetterPlacement": true,
34 |
35 | //启用更好的mod设置页面
36 | "enableBetterModsDialog": true,
37 |
38 | //=====KeyBinds/键位绑定=====//
39 |
40 | //实体信息控制热键
41 | "entityInfoHotKey": "altLeft",
42 |
43 | //快速物品栏翻页
44 | "switchFastPageHotKey": "tab",
45 | //展开/收起方块选择面板
46 | "placementFoldHotKey": "q",
47 |
48 | //=====Debug/调试设置=====//
49 |
50 | //启用加载信息
51 | "loadInfo": true,
52 | }
53 |
--------------------------------------------------------------------------------
/assets/shaders/dist_base.frag:
--------------------------------------------------------------------------------
1 |
2 | uniform sampler2D u_texture;
3 |
4 | varying vec2 v_texCoords;
5 |
6 | void main() {
7 | gl_FragColor.rgb = texture2D(u_texture, v_texCoords).rgb;
8 | gl_FragColor.a = 1.0;
9 | }
10 |
--------------------------------------------------------------------------------
/assets/shaders/entity_range.frag:
--------------------------------------------------------------------------------
1 | #define HIGHP
2 |
3 | uniform sampler2D u_texture;
4 |
5 | uniform vec2 u_campos;
6 | uniform vec2 u_resolution;
7 | uniform float u_time;
8 | uniform float u_stroke;
9 | uniform float u_alpha;
10 |
11 | varying vec2 v_texCoords;
12 |
13 | const float threshold = 0.01;
14 | const float PI = 3.14159265359;
15 |
16 | void main() {
17 | vec2 v = u_stroke*(1.0 / u_resolution);
18 |
19 | vec4 base = texture2D(u_texture, v_texCoords);
20 | vec2 worldCoord = vec2(v_texCoords.x * u_resolution.x + u_campos.x, v_texCoords.y * u_resolution.y + u_campos.y);
21 |
22 | //float m = min(min(min(
23 | // texture2D(u_texture, v_texCoords + vec2(1.0, 0.0) * v).a,
24 | // texture2D(u_texture, v_texCoords + vec2(0.0, 1.0) * v).a),
25 | // texture2D(u_texture, v_texCoords + vec2(-1.0, 0.0) * v).a),
26 | // texture2D(u_texture, v_texCoords + vec2(0.0, -1.0) * v).a);
27 |
28 | float m = min(min(min(min(min(min(min(
29 | texture2D(u_texture, v_texCoords + vec2(1.0, 0.0) * v).a,
30 | texture2D(u_texture, v_texCoords + vec2(0.7071, 0.7071) * v).a),
31 | texture2D(u_texture, v_texCoords + vec2(0.0, 1.0) * v).a),
32 | texture2D(u_texture, v_texCoords + vec2(-0.7071, 0.7071) * v).a),
33 | texture2D(u_texture, v_texCoords + vec2(-1.0, 0.0) * v).a),
34 | texture2D(u_texture, v_texCoords + vec2(-0.7071, -0.7071) * v).a),
35 | texture2D(u_texture, v_texCoords + vec2(0.0, -1.0) * v).a),
36 | texture2D(u_texture, v_texCoords + vec2(0.7071, -0.7071) * v).a);
37 |
38 | float time = u_time*0.1;
39 | float a =
40 | sin((worldCoord.x + worldCoord.y)*0.0831 + time*0.0095) +
41 | sin((-worldCoord.x + worldCoord.y)*0.075 + time*0.056) +
42 | sin((worldCoord.x - worldCoord.y)*0.0546 + time*0.21) +
43 | sin((-worldCoord.x - worldCoord.y)*0.03432 + time*0.712);
44 | a = (a/4.0 + 1.0)/2.0;
45 |
46 | float s = length(base.rgb);
47 |
48 | if(base.a > threshold && m < threshold) {
49 | gl_FragColor = vec4(s <= threshold? vec3(1.0): base.rgb, a);
50 | }
51 | else if (base.a >= threshold) {
52 | vec4 c1 = vec4(base.rgb, base.a*u_alpha);
53 | vec4 c2 = vec4(vec3(1.0), u_alpha);
54 | gl_FragColor = s <= threshold? mix(c1, c2, a): c1;
55 | }
56 | else {
57 | gl_FragColor = vec4(0.0);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/assets/sprites/ui/background.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/background.9.png
--------------------------------------------------------------------------------
/assets/sprites/ui/healthbar.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/healthbar.9.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/helium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/helium.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/java.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/java.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/javascript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/javascript.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/network-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/network-error.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/program.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/program.png
--------------------------------------------------------------------------------
/assets/sprites/ui/icons/slots-back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/icons/slots-back.png
--------------------------------------------------------------------------------
/assets/sprites/ui/shieldbar.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/assets/sprites/ui/shieldbar.9.png
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
3 | import java.io.FileOutputStream
4 | import java.io.InputStreamReader
5 | import java.io.StringReader
6 | import java.util.jar.JarEntry
7 | import java.util.jar.JarOutputStream
8 |
9 | val mindustryVersion = "v149"
10 | val arcVersion = "v149"
11 |
12 | val modOutputDir = properties["modOutputDir"] as? String
13 |
14 | val sdkRoot: String? = System.getenv("ANDROID_HOME")
15 |
16 | val buildDir = layout.buildDirectory.get()
17 | val projectName = project.name
18 |
19 | plugins {
20 | java
21 | kotlin("jvm") version "2.1.20"
22 | `maven-publish`
23 | }
24 |
25 | group = "com.github.EB-wilson"
26 | version = "beta-0.7"
27 |
28 | run { "java SyncBundles.java $version".execute() }
29 |
30 | java {
31 | sourceCompatibility = JavaVersion.VERSION_1_8
32 | targetCompatibility = JavaVersion.VERSION_1_8
33 | }
34 |
35 | kotlin {
36 | jvmToolchain(21)
37 |
38 | compilerOptions {
39 | jvmTarget.set(JvmTarget.JVM_1_8)
40 | }
41 | }
42 |
43 | publishing {
44 | publications {
45 | create("maven") {
46 | from(components["java"])
47 |
48 | groupId = "com.github.EB-wilson"
49 | artifactId = "TooManyItems"
50 | version = "${project.version}"
51 | }
52 | }
53 | }
54 |
55 | repositories {
56 | mavenLocal()
57 | mavenCentral()
58 | maven ("https://maven.xpdustry.com/mindustry")
59 | maven ("https://www.jitpack.io")
60 | }
61 |
62 | dependencies {
63 | compileOnly("com.github.Anuken.Arc:arc-core:$arcVersion")
64 | compileOnly("com.github.Anuken.Mindustry:core:$mindustryVersion")
65 |
66 | implementation("com.github.EB-wilson.UniverseCore:markdown:2.3.1")
67 |
68 | implementation(kotlin("stdlib-jdk8"))
69 | }
70 |
71 | tasks {
72 | jar {
73 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE
74 | archiveFileName = "${project.name}-desktop.jar"
75 |
76 | from(rootDir) {
77 | include("mod.hjson")
78 | include("icon.png")
79 | include("contributors.hjson")
80 | }
81 |
82 | from("assets/") {
83 | include("**")
84 | exclude("git")
85 | }
86 |
87 | from(configurations.getByName("runtimeClasspath").map { if (it.isDirectory) it else zipTree(it) })
88 | }
89 |
90 | register("jarAndroid") {
91 | dependsOn("jar")
92 |
93 | doLast {
94 | try {
95 | if (sdkRoot == null) throw GradleException("No valid Android SDK found. Ensure that ANDROID_HOME is set to your Android SDK directory.");
96 |
97 | val platformRoot = File("$sdkRoot/platforms/").listFiles()
98 | ?.sorted()
99 | ?.reversed()
100 | ?.find { f -> File (f, "android.jar").exists() }
101 |
102 | if (platformRoot == null) throw GradleException("No android.jar found. Ensure that you have an Android platform installed.")
103 |
104 | //collect dependencies needed for desugaring
105 | val dependencies = (
106 | configurations.compileClasspath.get().files +
107 | configurations.runtimeClasspath.get().files +
108 | setOf(File(platformRoot, "android.jar"))
109 | ).joinToString(" ") { "--classpath $it" }
110 |
111 | //dex and desugar files - this requires d8 in your PATH
112 | "d8 $dependencies --min-api 14 --output ${project.name}-android.jar ${project.name}-desktop.jar"
113 | .execute(File("$buildDir/libs"))
114 | }
115 | catch (e: Throwable) {
116 | if (e is Error){
117 | println(e.message)
118 | return@doLast
119 | }
120 |
121 | println("[WARNING] d8 tool or platform tools was not found, if you was installed android SDK, please check your environment variable")
122 |
123 | delete(
124 | files("${buildDir}/libs/${project.name}-android.jar")
125 | )
126 |
127 | val out = JarOutputStream(FileOutputStream("${buildDir}/libs/${project.name}-android.jar"))
128 | out.putNextEntry(JarEntry("non-androidMod.txt"))
129 | val reader = StringReader(
130 | "this mod is don't have classes.dex for android, please consider recompile with a SDK or run this mod on desktop only"
131 | )
132 |
133 | var r = reader.read()
134 | while (r != -1) {
135 | out.write(r)
136 | out.flush()
137 | r = reader.read()
138 | }
139 | out.close()
140 | }
141 | }
142 | }
143 |
144 | register("deploy", Jar::class) {
145 | dependsOn("jarAndroid")
146 | archiveFileName = "${project.name}.jar"
147 |
148 | from (
149 | zipTree("${buildDir}/libs/${project.name}-desktop.jar"),
150 | zipTree("${buildDir}/libs/${project.name}-android.jar")
151 | )
152 |
153 | doLast {
154 | if (!modOutputDir.isNullOrEmpty()) {
155 | copy {
156 | into("$modOutputDir/")
157 | from("${buildDir}/libs/${project.name}.jar")
158 | }
159 | }
160 | }
161 | }
162 |
163 | register("deployDesktop", Jar::class) {
164 | dependsOn("jar")
165 | archiveFileName = "${project.name}.jar"
166 |
167 | from (zipTree("${buildDir}/libs/${project.name}-desktop.jar"))
168 |
169 | doLast {
170 | if (!modOutputDir.isNullOrEmpty()) {
171 | copy {
172 | into("$modOutputDir/")
173 | from("${buildDir}/libs/${project.name}.jar")
174 | }
175 | }
176 | }
177 | }
178 |
179 | register("debugMod", JavaExec::class) {
180 | dependsOn("classes")
181 | dependsOn("deployDesktop")
182 |
183 | mainClass = "-jar"
184 | args = listOf(
185 | project.properties["debugGamePath"] as? String?:"",
186 | "-debug"
187 | )
188 | }
189 | }
190 |
191 | fun String.execute(path: File? = null, vararg args: Any?): Process{
192 | val cmd = split(Regex("\\s+"))
193 | .toMutableList()
194 | .apply { addAll(args.map { it?.toString()?:"null" }) }
195 | .toTypedArray()
196 | val process = ProcessBuilder(*cmd)
197 | .directory(path?:rootDir)
198 | .redirectOutput(ProcessBuilder.Redirect.INHERIT)
199 | .redirectError(ProcessBuilder.Redirect.INHERIT)
200 | .start()
201 |
202 | if (process.waitFor() != 0) throw Error(InputStreamReader(process.errorStream).readText())
203 |
204 | return process
205 | }
206 |
207 | class Error(str: String): RuntimeException(str)
208 |
--------------------------------------------------------------------------------
/bundleInfo.properties:
--------------------------------------------------------------------------------
1 | bundlesDir = assets/bundles/
2 |
3 | modName = he
4 | source = zh_CN
5 |
6 | targetLocales = [\
7 | en_US = (wait to translate)\
8 | zh_TW = (\u5F85\u7FFB\u8B6F)\
9 | ru = (\u043D\u0443\u0436\u0435\u043D \u043F\u0435\u0440\u0435\u0432\u043E\u0434)\
10 | ja = (\u7FFB\u8A33\u5F85\u3061)\
11 | de_DE = (\u00DCbersetzung w\u00FCnschen)\
12 | ]
13 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=--illegal-access=permit \
2 | --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
3 | --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
4 | --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
5 | --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
6 | --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
7 | --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
8 | --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
9 | --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
10 | --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
11 | --add-exports=jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \
12 | --add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
13 | --add-exports=java.base/sun.reflect.annotation=ALL-UNNAMED
14 |
15 | modOutputDir =
16 | debugGamePath =
17 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/icon.png
--------------------------------------------------------------------------------
/ktstools/genReflectCstrWrap.kts:
--------------------------------------------------------------------------------
1 | val builder = StringBuilder()
2 |
3 | for(n in 0..20){
4 | val typeArgs = StringBuilder()
5 | val typeArgsUse = StringBuilder()
6 | val types = StringBuilder()
7 | for (value in 1..n) {
8 | typeArgs.append("reified ").append("P").append(value).append(", ")
9 | typeArgsUse.append("P").append(value).append(", ")
10 | types.append("P").append(value).append("::class.java").append(", ")
11 | if (value%5 == 0) types.append("\n ")
12 | }
13 |
14 | val res =
15 | """
16 | inline fun 0) typeArgs.substring(0, typeArgs.length - 2) else typeArgs}> accessConstructor$n() =
17 | ConstructorInvoker$n<${typeArgsUse}O>(O::class.java.getConstructor(
18 | ${if (n > 0) types.substring(0, types.length - if (n % 5 == 0) 5 else 2) else types}
19 | ).also {
20 | it.isAccessible = true
21 | })"""
22 |
23 | builder.append(res)
24 | }
25 |
26 | System.out.print(builder.toString())
--------------------------------------------------------------------------------
/ktstools/genReflectCstrs.kts:
--------------------------------------------------------------------------------
1 |
2 | val builder = StringBuilder()
3 |
4 | for(n in 0..22){
5 | val typeArgs = StringBuilder()
6 | val argsDecl = StringBuilder()
7 | val args = StringBuilder()
8 | for (value in 1..n) {
9 | typeArgs.append("P").append(value).append(", ")
10 | argsDecl.append("p").append(value).append(": ").append("P").append(value).append(", ")
11 | args.append("p").append(value).append(", ")
12 | }
13 |
14 | val res =
15 | """
16 | class ConstructorInvoker$n<${typeArgs}O>(private val constructor: Constructor)
17 | : (${if (n > 0) typeArgs.substring(0, typeArgs.length - 2) else typeArgs}) -> O {
18 | override fun invoke(${if (n > 0) argsDecl.substring(0, argsDecl.length - 2) else ""})
19 | = constructor.newInstance(${if (n > 0) args.substring(0, args.length - 2) else ""})
20 | }"""
21 |
22 | builder.append(res)
23 | }
24 |
25 | System.out.print(builder.toString())
--------------------------------------------------------------------------------
/ktstools/genReflectMetWrap.kts:
--------------------------------------------------------------------------------
1 | val builder = StringBuilder()
2 |
3 | for(n in 0..20){
4 | val typeArgs = StringBuilder()
5 | val typeArgsUse = StringBuilder()
6 | val types = StringBuilder()
7 | for (value in 1..n) {
8 | typeArgs.append("reified ").append("P").append(value).append(", ")
9 | typeArgsUse.append("P").append(value).append(", ")
10 | types.append("P").append(value).append("::class.java").append(", ")
11 | if (value%5 == 0) types.append("\n ")
12 | }
13 |
14 | val res =
15 | """
16 | inline fun accessMethod$n(name: String) =
17 | MethodInvoker$n(O::class.java.getDeclaredMethod(
18 | name,
19 | ${if (n > 0) types.substring(0, types.length - if (n % 5 == 0) 5 else 2) else types}
20 | ).also {
21 | checkReturnType(it, R::class.java)
22 | it.isAccessible = true
23 | })"""
24 |
25 | builder.append(res)
26 | }
27 |
28 | System.out.print(builder.toString())
--------------------------------------------------------------------------------
/ktstools/genReflectMethods.kts:
--------------------------------------------------------------------------------
1 |
2 | val builder = StringBuilder()
3 |
4 | for(n in 0..22){
5 | val typeArgs = StringBuilder()
6 | val argsDecl = StringBuilder()
7 | val args = StringBuilder()
8 | for (value in 1..n) {
9 | typeArgs.append("P").append(value).append(", ")
10 | argsDecl.append("p").append(value).append(": ").append("P").append(value).append(", ")
11 | args.append("p").append(value).append(", ")
12 | }
13 |
14 | val res =
15 | """
16 | class MethodInvoker$n(private val method: Method)
17 | : (O, ${if (n > 0) typeArgs.substring(0, typeArgs.length - 2) else typeArgs}) -> R {
18 | override fun invoke(self: O, ${if (n > 0) argsDecl.substring(0, argsDecl.length - 2) else ""})
19 | = method.invoke(self, ${if (n > 0) args.substring(0, args.length - 2) else ""}) as R
20 | }"""
21 |
22 | builder.append(res)
23 | }
24 |
25 | System.out.print(builder.toString())
--------------------------------------------------------------------------------
/mod.hjson:
--------------------------------------------------------------------------------
1 | {
2 | displayName: "Helium",
3 | name: "he",
4 | author: "EBwilson",
5 | main: "helium.Helium",
6 | subtitle: "A mod provide optimized ui",
7 | description: '''
8 | A mod provide optimized ui and more utilities.
9 | Major features:
10 | - ***In-Game Entity Information Components***: Provides various UI elements for game entities including units and blocks
11 | - ***Health & Status Indicators***: Displays real-time status (health, shields) above units and entities. When shield stacks exceed max health, multi-layer shields with stack counters are shown.
12 | - ***Attack Range Indicators***: Units and turrets now visualize their attack ranges as translucent areas. Processed boundaries emphasize combined team range contours to prevent visual clutter, with subtle pulsating animations and chromatic borders.
13 | - ***Functional Block Effect Range Indicators***: Devices like Mend Projectors, Overdrive Projectors, and unit repair stations display effect ranges with distinctive colors.
14 | - ***Enhanced Block Placement Panel***: A refined block selection panel integrating a quick item bar and standardized tool buttons.
15 | - ***The better Mod Manager and Mod Browser***: Reworked the Mods Manager and Mods Browser, now they looks more aesthetically pleasing and functional
16 | ''',
17 | version: "beta-0.7",
18 | minGameVersion: 149,
19 | hidden: true
20 | }
--------------------------------------------------------------------------------
/preview_imgs/en/attackRange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/attackRange.png
--------------------------------------------------------------------------------
/preview_imgs/en/blur-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/blur-1.png
--------------------------------------------------------------------------------
/preview_imgs/en/blur-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/blur-2.png
--------------------------------------------------------------------------------
/preview_imgs/en/configEntry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/configEntry.png
--------------------------------------------------------------------------------
/preview_imgs/en/configurePane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/configurePane.png
--------------------------------------------------------------------------------
/preview_imgs/en/control-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/control-button.png
--------------------------------------------------------------------------------
/preview_imgs/en/effectRange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/effectRange.png
--------------------------------------------------------------------------------
/preview_imgs/en/modBrowser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/modBrowser.png
--------------------------------------------------------------------------------
/preview_imgs/en/modManager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/modManager.png
--------------------------------------------------------------------------------
/preview_imgs/en/placement-fold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/placement-fold.png
--------------------------------------------------------------------------------
/preview_imgs/en/placement-unfold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/placement-unfold.png
--------------------------------------------------------------------------------
/preview_imgs/en/quick-config-entry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/quick-config-entry.png
--------------------------------------------------------------------------------
/preview_imgs/en/quick-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/quick-config.png
--------------------------------------------------------------------------------
/preview_imgs/en/statusDisplay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/en/statusDisplay.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/attackRange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/attackRange.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/blur-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/blur-1.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/blur-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/blur-2.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/configEntry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/configEntry.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/configurePane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/configurePane.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/control-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/control-button.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/effectRange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/effectRange.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/modBrowser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/modBrowser.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/modManager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/modManager.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/placement-fold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/placement-fold.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/placement-unfold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/placement-unfold.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/quick-config-entry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/quick-config-entry.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/quick-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/quick-config.png
--------------------------------------------------------------------------------
/preview_imgs/zh_CN/statusDisplay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EB-wilson/Helium/20d6f03ceae4027b553ffe3f05237d60f553b310/preview_imgs/zh_CN/statusDisplay.png
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "Helium"
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/HeConfig.kt:
--------------------------------------------------------------------------------
1 | package helium
2 |
3 | import arc.files.Fi
4 | import arc.input.KeyCode
5 | import arc.util.Log
6 | import arc.util.Threads
7 | import arc.util.serialization.Jval
8 | import java.io.IOException
9 |
10 | private typealias RArray = java.lang.reflect.Array
11 |
12 | class HeConfig(configDir: Fi, internalSource: Fi) {
13 | companion object {
14 | private var exec = Threads.unboundedExecutor("HTTP", 1)
15 | private val commentMatcher = Regex("(//.*)|(/\\*(.|\\s)+\\*/)")
16 | private val keyMatcher = Regex("\"?(\\w+)\"?\\s*:\\s*")
17 | private val jsonArrayMatcher = Regex("\\[(.|\\s)*]")
18 | private val jsonObjectMatcher = Regex("\\{(.|\\s)*\\}")
19 | private val jsonValueMatcher = Regex("(\".*\")|([\\w.]+)")
20 |
21 | private val configs = HeConfig::class.java.declaredFields
22 | .filter { it.getAnnotation(ConfigItem::class.java) != null }
23 | }
24 |
25 | private val configFile = configDir.child("mod_config.hjson")
26 | private val configBack = configDir.child("mod_config.hjson.bak")
27 | private val internalConfigFile = internalSource
28 | private val configVersion = Jval.read(internalConfigFile.reader()).getInt("configVersion", 0)
29 |
30 | @ConfigItem var loadInfo = true
31 |
32 | @ConfigItem var enableBlur = true
33 | @ConfigItem var blurScl = 4
34 | @ConfigItem var blurSpace = 1.25f
35 |
36 | @ConfigItem var enableEntityInfoDisplay = true
37 | @ConfigItem var enableHealthBarDisplay = true
38 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
39 | @ConfigItem var hideHealthText = false
40 | @ConfigItem var enableUnitStatusDisplay = true
41 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
42 | @ConfigItem var enableRangeDisplay = true
43 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
44 | @ConfigItem var showAttackRange = true
45 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
46 | @ConfigItem var showHealRange = true
47 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
48 | @ConfigItem var showOverdriveRange = true
49 | set(value){ field = value; He.entityInfo.displaySetupUpdated() }
50 | @ConfigItem var entityInfoHotKey = KeyCode.altLeft
51 | @ConfigItem var entityInfoScale = 1f
52 | @ConfigItem var entityInfoAlpha = 1f
53 |
54 | @ConfigItem var enableBetterPlacement = true
55 | @ConfigItem var switchFastPageHotKey = KeyCode.tab
56 | @ConfigItem var placementFoldHotKey = KeyCode.q
57 |
58 | @ConfigItem var enableBetterModsDialog = true
59 |
60 | fun load() {
61 | if (!configFile.exists()) {
62 | internalConfigFile.copyTo(configFile)
63 | Log.info("Configuration file is not exist, copying the default configuration")
64 | load(configFile)
65 | } else {
66 | if (!load(configFile)) {
67 | val backup = configBack
68 | configFile.copyTo(backup)
69 | internalConfigFile.copyTo(configFile)
70 | Log.info("default configuration file version updated, old config should be override(backup file for old file was created)")
71 | save()
72 | }
73 | }
74 |
75 | if (loadInfo) printConfig()
76 | }
77 |
78 | private fun printConfig() {
79 | val results = StringBuilder()
80 |
81 | configs.forEach { cfg ->
82 | results.append(" ")
83 | .append(cfg.name)
84 | .append(" = ")
85 | .append(
86 | cfg.get(this).let {
87 | when(it){
88 | is Array<*> -> it.contentToString()
89 | is ByteArray -> it.contentToString()
90 | is ShortArray -> it.contentToString()
91 | is IntArray -> it.contentToString()
92 | is LongArray -> it.contentToString()
93 | is FloatArray -> it.contentToString()
94 | is DoubleArray -> it.contentToString()
95 | is CharArray -> it.contentToString()
96 | is BooleanArray -> it.contentToString()
97 | else -> it.toString()
98 | }
99 | }
100 | )
101 | .append(";")
102 | .append(System.lineSeparator())
103 | }
104 |
105 | Log.info("Mod config loaded! The config data:[${System.lineSeparator()}$results]")
106 | }
107 |
108 | private fun load(file: Fi): Boolean {
109 | val sb = StringBuilder()
110 | file.reader().use { reader ->
111 | val part = CharArray(8192)
112 | var n: Int
113 | while (reader.read(part, 0, part.size).also { n = it } != -1) {
114 | sb.appendRange(part, 0, n)
115 | }
116 | }
117 |
118 | val config = Jval.read(file.reader())
119 |
120 | val old = config.get("configVersion").asInt() != configVersion
121 |
122 | configs.forEach { cfg ->
123 | if (!config.has(cfg.name)) return@forEach
124 |
125 | val temp = config.get(cfg.name).toString()
126 | cfg.set(this, warp(cfg.type, temp))
127 | }
128 |
129 | return !old
130 | }
131 |
132 | fun saveAsync() {
133 | exec.submit {
134 | synchronized(this, ::save)
135 | }
136 | }
137 |
138 | fun save() {
139 | try {
140 | save(configFile)
141 | } catch (e: IOException) {
142 | Log.err(e.toString())
143 | }
144 | }
145 |
146 | @Suppress("UNCHECKED_CAST")
147 | private fun save(file: Fi) {
148 | val tree = Jval.newObject()
149 | val map = tree.asObject()
150 | map.put("configVersion", Jval.valueOf(configVersion))
151 |
152 | configs.forEach { cfg ->
153 | val key = cfg.name
154 | val obj = cfg.get(this)
155 | when {
156 | obj == null -> when {
157 | CharSequence::class.java.isAssignableFrom(cfg.type) -> map.put(key, Jval.valueOf(""))
158 | cfg.type.isArray -> map.put(key, Jval.newArray())
159 | cfg.type.isEnum -> map.put(key, Jval.valueOf(firstEnum(cfg.type as Class>).name))
160 | else -> throw RuntimeException("Unhandled null type")
161 | }
162 | else -> map.put(key, pack(obj))
163 | }
164 | }
165 |
166 | val stringBuilder = StringBuilder()
167 |
168 | val fileContext = file.reader().readText()
169 | var lastStart = 0
170 | commentMatcher.findAll(fileContext).forEach { res ->
171 | val end = res.range.first
172 | val subString = fileContext.substring(lastStart, end)
173 |
174 | handleText(subString, stringBuilder, map)
175 |
176 | stringBuilder.append(res.value)
177 |
178 | lastStart = res.range.last + 1
179 | }
180 | if (lastStart < fileContext.length) {
181 | val subString = fileContext.substring(lastStart)
182 | handleText(subString, stringBuilder, map)
183 | }
184 |
185 | file.writeString(stringBuilder.toString())
186 | }
187 |
188 | private fun handleText(
189 | subString: String,
190 | stringBuilder: StringBuilder,
191 | map: Jval.JsonMap,
192 | ) {
193 | var lastKeyEnd = 0
194 | keyMatcher.findAll(subString).forEach pair@{ key ->
195 | val keyName = key.groups[1]!!
196 |
197 | val perpend = subString.substring(lastKeyEnd, key.range.first)
198 | stringBuilder.append(perpend)
199 |
200 | stringBuilder.append(key.value)
201 | stringBuilder.append(map.get(keyName.value))
202 |
203 | lastKeyEnd = key.range.last + 1
204 | }
205 | if (lastKeyEnd < subString.length) {
206 | stringBuilder.append(
207 | subString
208 | .substring(lastKeyEnd)
209 | .replace(jsonValueMatcher, "")
210 | .replace(jsonArrayMatcher, "")
211 | .replace(jsonObjectMatcher, "")
212 | )
213 | }
214 | }
215 |
216 | private fun pack(value: Any): Jval {
217 | return when (value) {
218 | is Int -> Jval.valueOf(value)
219 | is Byte -> Jval.valueOf(value.toInt())
220 | is Short -> Jval.valueOf(value.toInt())
221 | is Boolean -> Jval.valueOf(value)
222 | is Long -> Jval.valueOf(value)
223 | is Char -> Jval.valueOf(value.code)
224 | is Float -> Jval.valueOf(value)
225 | is Double -> Jval.valueOf(value)
226 | is CharSequence -> Jval.valueOf(value.toString())
227 | else -> when {
228 | value.javaClass.isArray -> packArray(value)
229 | value.javaClass.isEnum -> Jval.valueOf((value as Enum<*>).name)
230 | else -> throw RuntimeException("invalid type: ${value.javaClass}")
231 | }
232 | }
233 | }
234 |
235 | private fun packArray(array: Any): Jval {
236 | if (!array.javaClass.isArray) throw RuntimeException("given object was not an array")
237 |
238 | val len = RArray.getLength(array)
239 | val res = Jval.newArray()
240 | val arr = res.asArray()
241 | (0 until len).forEach { i ->
242 | arr.add(pack(RArray.get(array, i)))
243 | }
244 | return res
245 | }
246 |
247 | @Suppress("UNCHECKED_CAST")
248 | private fun warp(type: Class, value: String): T {
249 | return when (type) {
250 | Int::class.java -> value.toInt() as T
251 | Byte::class.java -> value.toByte() as T
252 | Short::class.java -> value.toShort() as T
253 | Boolean::class.java -> value.toBoolean() as T
254 | Long::class.java -> value.toLong() as T
255 | Char::class.java -> value[0] as T
256 | Float::class.java -> value.toFloat() as T
257 | Double::class.java -> value.toDouble() as T
258 | else -> when {
259 | CharSequence::class.java.isAssignableFrom(type) -> value as T
260 | type.isArray -> toArray(type, value)
261 | type.isEnum -> (type as Class>).enumConstants.find { it.name == value } as T
262 | else -> throw RuntimeException("invalid type: $type")
263 | }
264 | }
265 | }
266 |
267 | @Suppress("UNCHECKED_CAST")
268 | private fun toArray(type: Class, value: String): T {
269 | if (!type.isArray) throw RuntimeException("class $type was not an array")
270 | val a = Jval.read(value).asArray()
271 | val eleType = type.componentType
272 | val res = RArray.newInstance(eleType, a.size)
273 | (0 until a.size).forEach { i ->
274 | RArray.set(res, i, warp(eleType, a[i].toString()))
275 | }
276 | return res as T
277 | }
278 |
279 | private fun > firstEnum(type: Class): T {
280 | if (!type.isEnum) throw RuntimeException("class $type was not an enum")
281 |
282 | return type.enumConstants[0]
283 | }
284 |
285 | fun reset() {
286 | configFile.copyTo(configBack)
287 | configFile.delete()
288 | Log.info("[INFO][${He.MOD_NAME}] mod config has been reset, old config file saved to file named \"mod_config.hjson.bak\"")
289 | load()
290 | }
291 | }
292 |
293 | @Retention(AnnotationRetention.RUNTIME)
294 | @Target(AnnotationTarget.FIELD)
295 | annotation class ConfigItem
296 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/Helium.kt:
--------------------------------------------------------------------------------
1 | package helium
2 |
3 | import arc.Core
4 | import arc.files.Fi
5 | import arc.graphics.g2d.TextureRegion
6 | import arc.scene.style.Drawable
7 | import helium.graphics.ScreenSampler
8 | import mindustry.mod.Mod
9 |
10 | class Helium : Mod() {
11 | init {
12 | ScreenSampler.resetMark()
13 | }
14 |
15 | override fun init() {
16 | ScreenSampler.setup()
17 |
18 | He.init()
19 | }
20 |
21 | companion object {
22 | fun getInternalFile(path: String): Fi {
23 | return He.modFile.child(path)
24 | }
25 |
26 | fun getDrawable(spriteName: String): T =
27 | Core.atlas.getDrawable("${He.INTERNAL_NAME}-$spriteName")
28 | fun getAtlas(spriteName: String): TextureRegion =
29 | Core.atlas.find("${He.INTERNAL_NAME}-$spriteName")
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/BaseClipDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.scene.style.BaseDrawable
4 |
5 | abstract class BaseClipDrawable(): ClipDrawable {
6 | @Suppress("LeakingThis")
7 | constructor(other: ClipDrawable): this(){
8 | if (other is BaseDrawable) name = other.name
9 | leftWidth = other.leftWidth
10 | rightWidth = other.rightWidth
11 | topHeight = other.topHeight
12 | bottomHeight = other.bottomHeight
13 | minWidth = other.minWidth
14 | minHeight = other.minHeight
15 | }
16 |
17 | var name: String? = null
18 | override var leftWidth: Float = 0f
19 | override var rightWidth: Float = 0f
20 | override var topHeight: Float = 0f
21 | override var bottomHeight: Float = 0f
22 | override var minWidth: Float = 0f
23 | override var minHeight: Float = 0f
24 |
25 | override fun toString(): String {
26 | if (name == null) return javaClass.toString()
27 | return name!!
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/BaseStripDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | abstract class BaseStripDrawable: StripDrawable {
4 | override var leftOff: Float = 0f
5 | override var rightOff: Float = 0f
6 | override var outerWidth: Float = 0f
7 | override var innerWidth: Float = 0f
8 | override var minOffset: Float = 0f
9 | override var minWidth: Float = 0f
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/Blur.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.Core
4 | import arc.graphics.Blending
5 | import arc.graphics.Color
6 | import arc.graphics.gl.FrameBuffer
7 | import arc.graphics.gl.Shader
8 | import arc.util.Log
9 | import kotlin.math.abs
10 |
11 | val DEf_A: FloatArray = floatArrayOf(
12 | 0.008697324f, 0.035994977f, 0.10936101f,
13 | 0.21296589f, 0.26596153f, 0.21296589f,
14 | 0.10936101f, 0.035994977f, 0.008697324f,
15 | )
16 | val DEf_B: FloatArray = floatArrayOf(
17 | 0.044408645f, 0.07799442f, 0.11599662f,
18 | 0.16730806f, 0.1885769f, 0.16730806f,
19 | 0.11599662f, 0.07799442f, 0.044408645f,
20 | )
21 | val DEf_C: FloatArray = floatArrayOf(
22 | 0.0045418483f, 0.053999867f, 0.24198672f,
23 | 0.39894313f,
24 | 0.24198672f, 0.053999867f, 0.0045418483f,
25 | )
26 | val DEf_D: FloatArray = floatArrayOf(
27 | 0.02454185f, 0.06399987f, 0.2519867f,
28 | 0.3189431f,
29 | 0.2519867f, 0.06399987f, 0.02454185f,
30 | )
31 | val DEf_E: FloatArray = floatArrayOf(
32 | 0.01961571f, 0.20542552f,
33 | 0.55991757f,
34 | 0.20542552f, 0.01961571f,
35 | )
36 | val DEf_F: FloatArray = floatArrayOf(
37 | 0.07027027f, 0.31621623f,
38 | 0.22702703f,
39 | 0.31621623f, 0.07027027f,
40 | )
41 | val DEf_G: FloatArray = floatArrayOf(
42 | 0.20798193f,
43 | 0.68403614f,
44 | 0.20798193f,
45 | )
46 | val DEf_H: FloatArray = floatArrayOf(
47 | 0.25617367f,
48 | 0.4876527f,
49 | 0.25617367f,
50 | )
51 |
52 | private const val vertTemplate =
53 | """
54 | attribute vec4 a_position;
55 | attribute vec2 a_texCoord0;
56 |
57 | uniform vec2 u_dir;
58 | uniform vec2 u_size;
59 |
60 | varying vec2 v_texCoords;
61 |
62 | %varying%
63 |
64 | void main(){
65 | vec2 len = u_dir/u_size;
66 |
67 | v_texCoords = a_texCoord0;
68 | %assignVar%
69 | gl_Position = a_position;
70 | }
71 | """
72 | private const val fragmentTemplate =
73 | """
74 | uniform lowp sampler2D u_texture0;
75 | uniform lowp sampler2D u_texture1;
76 |
77 | uniform lowp float u_def_alpha;
78 |
79 | varying vec2 v_texCoords;
80 |
81 | %varying%
82 |
83 | void main(){
84 | vec4 blur = texture2D(u_texture0, v_texCoords);
85 | vec3 color = texture2D(u_texture1, v_texCoords).rgb;
86 |
87 | if(blur.a > 0.0){
88 | vec3 blurColor =
89 | %convolution%
90 |
91 | gl_FragColor.rgb = mix(color, blurColor, blur.a);
92 | gl_FragColor.a = 1.0;
93 | }
94 | else{
95 | gl_FragColor.rgb = color;
96 | gl_FragColor.a = u_def_alpha;
97 | }
98 | }
99 | """
100 |
101 | class Blur(vararg convolutions: Float = DEf_F) {
102 | var blurShader: Shader
103 | var buffer: FrameBuffer
104 | var pingpong: FrameBuffer
105 |
106 | var capturing: Boolean = false
107 |
108 | var blurScl: Int = 4
109 | var blurSpace: Float = 2.16f
110 |
111 | init {
112 | blurShader = genShader(*convolutions)
113 |
114 | buffer = FrameBuffer()
115 | pingpong = FrameBuffer()
116 |
117 | blurShader.bind()
118 | blurShader.setUniformi("u_texture0", 0)
119 | blurShader.setUniformi("u_texture1", 1)
120 | }
121 |
122 | private fun genShader(vararg convolutions: Float): Shader {
123 | require(convolutions.size%2 == 1) { "convolution numbers length must be odd number!" }
124 |
125 | val convLen = convolutions.size
126 |
127 | val varyings = StringBuilder()
128 | val assignVar = StringBuilder()
129 | val convolution = StringBuilder()
130 |
131 | var c = 0
132 | val half = convLen/2
133 | for (v in convolutions) {
134 | varyings.append("varying vec2 v_texCoords")
135 | .append(c)
136 | .append(";")
137 | .append("\n")
138 |
139 | assignVar.append("v_texCoords")
140 | .append(c)
141 | .append(" = ")
142 | .append("a_texCoord0")
143 | if (c - half != 0) {
144 | assignVar.append(if (c - half > 0) "+" else "-")
145 | .append(abs((c.toFloat() - half).toDouble()).toFloat())
146 | .append("*len")
147 | }
148 | assignVar.append(";")
149 | .append("\n")
150 | .append(" ")
151 |
152 | if (c > 0) convolution.append(" + ")
153 | convolution.append(v)
154 | .append("*texture2D(u_texture1, v_texCoords")
155 | .append(c)
156 | .append(")")
157 | .append(".rgb")
158 | .append("\n")
159 |
160 | c++
161 | }
162 | convolution.append(";")
163 |
164 | val vertexShader = vertTemplate
165 | .replace("%varying%", varyings.toString())
166 | .replace("%assignVar%", assignVar.toString())
167 | val fragmentShader = fragmentTemplate
168 | .replace("%varying%", varyings.toString())
169 | .replace("%convolution%", convolution.toString())
170 |
171 | Log.info(vertexShader)
172 | Log.info(fragmentShader)
173 |
174 | return Shader(vertexShader, fragmentShader)
175 | }
176 |
177 | fun resize(width: Int, height: Int) {
178 | val w = width/blurScl
179 | val h = height/blurScl
180 |
181 | buffer.resize(w, h)
182 | pingpong.resize(w, h)
183 |
184 | blurShader.bind()
185 | blurShader.setUniformf("u_size", w.toFloat(), h.toFloat())
186 | }
187 |
188 | fun capture() {
189 | if (!capturing) {
190 | buffer.begin(Color.clear)
191 |
192 | capturing = true
193 | }
194 | }
195 |
196 | fun render() {
197 | if (!capturing) return
198 | capturing = false
199 | buffer.end()
200 |
201 | Blending.disabled.apply()
202 |
203 | blurShader.bind()
204 | blurShader.apply()
205 | blurShader.setUniformf("u_dir", blurSpace, 0f)
206 | blurShader.setUniformf("u_def_alpha", 1f)
207 | buffer.texture.bind(0)
208 |
209 | pingpong.begin()
210 | ScreenSampler.blit(blurShader, 1)
211 | pingpong.end()
212 |
213 | blurShader.setUniformf("u_dir", 0f, blurSpace)
214 | blurShader.setUniformf("u_def_alpha", 0f)
215 | pingpong.texture.bind(1)
216 |
217 | Blending.normal.apply()
218 | buffer.blit(blurShader)
219 | }
220 |
221 | fun directDraw(draw: Runnable) {
222 | resize(Core.graphics.width, Core.graphics.height)
223 | capture()
224 | draw.run()
225 | render()
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/ClipDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | interface ClipDrawable {
4 | fun draw(
5 | x: Float, y: Float,
6 | width: Float, height: Float,
7 | clipLeft: Float, clipRight: Float,
8 | clipTop: Float, clipBottom: Float
9 | )
10 | fun draw(
11 | x: Float, y: Float,
12 | originX: Float, originY: Float,
13 | width: Float, height: Float,
14 | scaleX: Float, scaleY: Float,
15 | rotation: Float,
16 | clipLeft: Float, clipRight: Float,
17 | clipTop: Float, clipBottom: Float
18 | )
19 | var leftWidth: Float
20 | var rightWidth: Float
21 | var topHeight: Float
22 | var bottomHeight: Float
23 | var minWidth: Float
24 | var minHeight: Float
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/EdgeLineStripDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.graphics.Color
4 | import arc.graphics.g2d.Draw
5 | import arc.graphics.g2d.Lines
6 | import arc.math.Mathf
7 | import arc.util.Tmp
8 |
9 |
10 | class EdgeLineStripDrawable(
11 | val stroke: Float,
12 | val lineColor: Color,
13 | color: Color = Color.clear,
14 | innerColor: Color = color,
15 | ): FillStripDrawable(color, innerColor) {
16 | override fun draw(
17 | originX: Float,
18 | originY: Float,
19 | angle: Float,
20 | distance: Float,
21 | angleDelta: Float,
22 | stripWidth: Float,
23 | ) {
24 | super.draw(originX, originY, angle, distance, angleDelta, stripWidth)
25 | Draw.color(Tmp.c1.set(lineColor).mul(Draw.getColor()).toFloatBits())
26 | Lines.stroke(stroke)
27 | if (stripWidth <= 0) {
28 | Lines.arc(
29 | originX, originY,
30 | distance, angleDelta/360f,
31 | angle
32 | )
33 | }
34 | else if (angleDelta <= 0) {
35 | val cos = Mathf.cosDeg(angle)
36 | val sin = Mathf.sinDeg(angle)
37 | val inOffX = distance * cos
38 | val inOffY = distance * sin
39 | val outOffX = (distance + stripWidth) * cos
40 | val outOffY = (distance + stripWidth) * sin
41 | Lines.line(
42 | originX + inOffX,
43 | originY + inOffY,
44 | originX + outOffX,
45 | originY + outOffY,
46 | )
47 | }
48 | else DrawUtils.circleFrame(
49 | originX, originY,
50 | distance, distance + stripWidth,
51 | angleDelta, angle,
52 | padCap = true
53 | )
54 | }
55 |
56 | fun tint(
57 | stroke: Float,
58 | lineColor: Color,
59 | color: Color = this.color,
60 | innerColor: Color = this.innerColor,
61 | ): EdgeLineStripDrawable {
62 | return EdgeLineStripDrawable(stroke, lineColor, color, innerColor)
63 | }
64 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/FillStripDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.graphics.Color
4 | import arc.graphics.g2d.Draw
5 | import arc.util.Tmp
6 |
7 | open class FillStripDrawable(
8 | val color: Color,
9 | val innerColor: Color = color,
10 | ): BaseStripDrawable() {
11 | override fun draw(
12 | originX: Float, originY: Float,
13 | angle: Float, distance: Float,
14 | angleDelta: Float, stripWidth: Float
15 | ) {
16 | DrawUtils.circleStrip(
17 | originX, originY,
18 | distance, distance + stripWidth,
19 | angleDelta, angle,
20 | Tmp.c1.set(innerColor).mul(Draw.getColor()),
21 | Tmp.c2.set(color).mul(Draw.getColor())
22 | )
23 | }
24 |
25 | open fun tint(color: Color, innerColor: Color = color): FillStripDrawable {
26 | return FillStripDrawable(color, innerColor)
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/HeShaders.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.Core
4 | import arc.files.Fi
5 | import arc.graphics.gl.Shader
6 | import helium.Helium.Companion.getInternalFile
7 | import helium.graphics.g2d.EntityRangeExtractor
8 |
9 | object HeShaders {
10 | lateinit var entityRangeRenderer: EntityRangeExtractor
11 |
12 | lateinit var baseScreen: Shader
13 |
14 | private val internalShaderDir: Fi = getInternalFile("shaders")
15 |
16 | fun load() {
17 | entityRangeRenderer = EntityRangeExtractor()
18 |
19 | baseScreen = Shader(
20 | Core.files.internal("shaders/screenspace.vert"),
21 | internalShaderDir.child("dist_base.frag")
22 | )
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/LazyDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.func.Prov
4 | import arc.scene.style.Drawable
5 |
6 | class LazyDrawable(
7 | private val prov: Prov
8 | ): Drawable {
9 | private var drawable: Drawable? = null
10 |
11 | private fun check(){
12 | if (drawable == null) drawable = prov.get()
13 | }
14 |
15 | override fun draw(x: Float, y: Float, width: Float, height: Float) {
16 | check()
17 | drawable!!.draw(x, y, width, height)
18 | }
19 |
20 | override fun draw(
21 | x: Float, y: Float, originX: Float, originY: Float,
22 | width: Float, height: Float, scaleX: Float, scaleY: Float,
23 | rotation: Float,
24 | ) {
25 | check()
26 | drawable!!.draw(x, y, originX, originY, width, height, scaleX, scaleY, rotation)
27 | }
28 |
29 | override fun getLeftWidth() = drawable?.leftWidth?:0f
30 | override fun setLeftWidth(leftWidth: Float) { drawable?.leftWidth = leftWidth }
31 | override fun getRightWidth() = drawable?.rightWidth?:0f
32 | override fun setRightWidth(rightWidth: Float) { drawable?.rightWidth = rightWidth }
33 | override fun getTopHeight() = drawable?.topHeight?:0f
34 | override fun setTopHeight(topHeight: Float) { drawable?.topHeight = topHeight }
35 | override fun getBottomHeight() = drawable?.bottomHeight?:0f
36 | override fun setBottomHeight(bottomHeight: Float) { drawable?.bottomHeight = bottomHeight }
37 |
38 | override fun getMinWidth() = drawable?.minWidth?:0f
39 | override fun setMinWidth(minWidth: Float) { drawable?.minWidth = minWidth }
40 | override fun getMinHeight() = drawable?.minHeight?:0f
41 | override fun setMinHeight(minHeight: Float) { drawable?.minHeight = minHeight }
42 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/ScaledNinePatchClipDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.graphics.g2d.NinePatch
4 | import arc.scene.style.NinePatchDrawable
5 | import arc.scene.ui.layout.Scl
6 |
7 | open class ScaledNinePatchClipDrawable : NinePatchClipDrawable {
8 | open val scale get() = Scl.scl(1f)
9 |
10 | /** Creates an uninitialized NinePatchDrawable. The ninepatch must be [setPatch] before use. */
11 | constructor(): super()
12 | constructor(patch: NinePatch): super(patch)
13 | constructor(drawable: NinePatchClipDrawable): super(drawable)
14 | constructor(drawable: NinePatchDrawable): super(drawable.patch!!)
15 |
16 | override fun draw(
17 | x: Float, y: Float, width: Float, height: Float,
18 | clipLeft: Float, clipRight: Float, clipTop: Float, clipBottom: Float
19 | ) {
20 | val scale = scale
21 | draw(
22 | x, y, 0f, 0f,
23 | width/scale, height/scale, scale, scale, 0f,
24 | clipLeft/scale, clipRight/scale, clipTop/scale, clipBottom/scale
25 | )
26 | }
27 |
28 | override fun setPatch(patch: NinePatch) {
29 | super.setPatch(patch)
30 |
31 | minWidth = patch.totalWidth*scale
32 | minHeight = patch.totalHeight*scale
33 | }
34 |
35 | override var leftWidth: Float
36 | get() = ninePatch.padLeft*scale
37 | set(_) {}
38 | override var rightWidth: Float
39 | get() = ninePatch.padRight*scale
40 | set(_) {}
41 | override var topHeight: Float
42 | get() = ninePatch.padTop*scale
43 | set(_) {}
44 | override var bottomHeight: Float
45 | get() = ninePatch.padBottom*scale
46 | set(_) {}
47 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/ScreenSampler.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | import arc.Core
4 | import arc.Events
5 | import arc.graphics.Color
6 | import arc.graphics.GL30
7 | import arc.graphics.Gl
8 | import arc.graphics.g2d.Draw
9 | import arc.graphics.gl.FrameBuffer
10 | import arc.graphics.gl.Shader
11 | import arc.util.serialization.Jval
12 | import mindustry.game.EventType
13 |
14 | object ScreenSampler {
15 | private var worldBuffer: FrameBuffer? = null
16 | private var uiBuffer: FrameBuffer? = null
17 |
18 | private var currBuffer: FrameBuffer? = null
19 | private var activity = false
20 |
21 | fun resetMark() {
22 | Core.settings.remove("sampler.setup")
23 | }
24 |
25 | fun setup() {
26 | if (activity) throw RuntimeException("forbid setup sampler twice")
27 |
28 | var e = Jval.read(Core.settings.getString("sampler.setup", "{enabled: false}"))
29 |
30 | if (!e.getBool("enabled", false)) {
31 | e = Jval.newObject()
32 | e.put("enabled", true)
33 | e.put("className", ScreenSampler::class.java.name)
34 | e.put("worldBuffer", "worldBuffer")
35 | e.put("uiBuffer", "uiBuffer")
36 |
37 | worldBuffer = FrameBuffer()
38 | uiBuffer = FrameBuffer()
39 |
40 | Core.settings.put("sampler.setup", e.toString())
41 |
42 | Events.run(EventType.Trigger.preDraw) { beginWorld() }
43 | Events.run(EventType.Trigger.postDraw) { endWorld() }
44 |
45 | Events.run(EventType.Trigger.uiDrawBegin) { beginUI() }
46 | Events.run(EventType.Trigger.uiDrawEnd) { endUI() }
47 | }
48 | else {
49 | val className = e.getString("className")
50 | val worldBufferName = e.getString("worldBuffer")
51 | val uiBufferName = e.getString("uiBuffer")
52 | val clazz = Class.forName(className)
53 | val worldBufferField = clazz.getDeclaredField(worldBufferName)
54 | val uiBufferField = clazz.getDeclaredField(uiBufferName)
55 |
56 | worldBufferField.isAccessible = true
57 | uiBufferField.isAccessible = true
58 | worldBuffer = worldBufferField[null] as FrameBuffer
59 | uiBuffer = uiBufferField[null] as FrameBuffer
60 |
61 | Events.run(EventType.Trigger.preDraw) { currBuffer = worldBuffer }
62 | Events.run(EventType.Trigger.postDraw) { currBuffer = null }
63 | Events.run(EventType.Trigger.uiDrawBegin) { currBuffer = uiBuffer }
64 | Events.run(EventType.Trigger.uiDrawEnd) { currBuffer = null }
65 | }
66 |
67 | activity = true
68 | }
69 |
70 | private fun beginWorld() {
71 | currBuffer = worldBuffer
72 | worldBuffer!!.resize(Core.graphics.width, Core.graphics.height)
73 | worldBuffer!!.begin(Color.clear)
74 | }
75 |
76 | private fun endWorld() {
77 | currBuffer = null
78 | worldBuffer!!.end()
79 | }
80 |
81 | private fun beginUI() {
82 | currBuffer = uiBuffer
83 | uiBuffer!!.resize(Core.graphics.width, Core.graphics.height)
84 | uiBuffer!!.begin(Color.clear)
85 | blitBuffer(worldBuffer!!, uiBuffer)
86 | }
87 |
88 | private fun endUI() {
89 | currBuffer = null
90 | uiBuffer!!.end()
91 | blitBuffer(uiBuffer!!, null)
92 | }
93 |
94 | /**将当前的屏幕纹理使用传入的着色器绘制到屏幕上
95 | * @param unit 屏幕采样纹理绑定的纹理单元
96 | */
97 | fun blit(shader: Shader, unit: Int = 0) {
98 | checkNotNull(currBuffer) { "currently no buffer bound" }
99 |
100 | currBuffer!!.texture.bind(unit)
101 | Draw.blit(shader)
102 | }
103 |
104 | private fun blitBuffer(from: FrameBuffer, to: FrameBuffer?) {
105 | if (Core.gl30 == null) {
106 | from.blit(HeShaders.baseScreen)
107 | }
108 | else {
109 | Gl.bindFramebuffer(GL30.GL_READ_FRAMEBUFFER, from.framebufferHandle)
110 | Gl.bindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, to?.framebufferHandle ?: 0)
111 | Core.gl30.glBlitFramebuffer(
112 | 0, 0, from.width, from.height,
113 | 0, 0,
114 | to?.width ?: Core.graphics.width,
115 | to?.height ?: Core.graphics.height,
116 | Gl.colorBufferBit, Gl.nearest
117 | )
118 | }
119 | }
120 |
121 | /**将当前屏幕纹理转存到一个[帧缓冲区][FrameBuffer],这将成为一份拷贝,可用于暂存屏幕内容
122 | *
123 | * @param target 用于转存屏幕纹理的目标缓冲区
124 | * @param clear 在转存之前是否清空帧缓冲区
125 | */
126 | fun getToBuffer(target: FrameBuffer, clear: Boolean) {
127 | checkNotNull(currBuffer) { "currently no buffer bound" }
128 |
129 | if (clear) target.begin(Color.clear)
130 | else target.begin()
131 |
132 | Gl.bindFramebuffer(GL30.GL_READ_FRAMEBUFFER, currBuffer!!.framebufferHandle)
133 | Gl.bindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, target.framebufferHandle)
134 | Core.gl30.glBlitFramebuffer(
135 | 0, 0, currBuffer!!.width, currBuffer!!.height,
136 | 0, 0, target.width, target.height,
137 | Gl.colorBufferBit, Gl.nearest
138 | )
139 |
140 | target.end()
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/StripDrawable.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics
2 |
3 | interface StripDrawable {
4 | fun draw(originX: Float, originY: Float, stripWidth: Float, angleDelta: Float) =
5 | draw(originX, originY, 0f, 0f, angleDelta, stripWidth)
6 | fun draw(originX: Float, originY: Float, angle: Float, distance: Float, angleDelta: Float, stripWidth: Float)
7 | var leftOff: Float
8 | var rightOff: Float
9 | var outerWidth: Float
10 | var innerWidth: Float
11 | var minOffset: Float
12 | var minWidth: Float
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/graphics/g2d/EntityRangeExtractor.kt:
--------------------------------------------------------------------------------
1 | package helium.graphics.g2d
2 |
3 | import arc.Core
4 | import arc.files.Fi
5 | import arc.graphics.Color
6 | import arc.graphics.Texture
7 | import arc.graphics.gl.FrameBuffer
8 | import arc.graphics.gl.Shader
9 | import arc.util.Time
10 | import helium.Helium.Companion.getInternalFile
11 |
12 | class EntityRangeExtractor {
13 | companion object {
14 | private val internalShaderDir: Fi = getInternalFile("shaders")
15 | }
16 |
17 | private val buffer = FrameBuffer().also { it.texture.setFilter(Texture.TextureFilter.nearest) }
18 | init {
19 | setupShader()
20 | }
21 |
22 | private var capturing = false
23 |
24 | var stroke = 2f
25 | var alpha = 0.075f
26 |
27 | private lateinit var extractShader: Shader
28 |
29 | private fun setupShader() {
30 | extractShader = Shader(
31 | Core.files.internal("shaders/screenspace.vert"),
32 | internalShaderDir.child("entity_range.frag")
33 | )
34 | buffer.resize(Core.graphics.width, Core.graphics.height)
35 | }
36 |
37 | fun capture(){
38 | if (capturing) throw IllegalStateException("capturing already running")
39 |
40 | buffer.resize(Core.graphics.width, Core.graphics.height)
41 | buffer.begin(Color.clear)
42 | capturing = true
43 | }
44 |
45 | fun render(){
46 | if (!capturing) throw IllegalStateException("capturing not started")
47 |
48 | capturing = false
49 |
50 | buffer.end()
51 | extractShader.also{
52 | it.bind()
53 | it.apply()
54 | it.setUniformf("u_time", Time.time)
55 | it.setUniformf("u_resolution", Core.camera.width, Core.camera.height)
56 | it.setUniformf(
57 | "u_campos",
58 | Core.camera.position.x - Core.camera.width/2,
59 | Core.camera.position.y - Core.camera.height/2
60 | )
61 | it.setUniformf("u_stroke", stroke)
62 | it.setUniformf("u_alpha", alpha)
63 | it.setUniformi("u_texture", 0)
64 | buffer.blit(it)
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/ui/HeAssets.kt:
--------------------------------------------------------------------------------
1 | package helium.ui
2 |
3 | import arc.graphics.Color
4 | import arc.graphics.g2d.Lines
5 | import arc.scene.style.BaseDrawable
6 | import arc.scene.style.Drawable
7 | import arc.scene.style.TextureRegionDrawable
8 | import arc.scene.ui.layout.Scl
9 | import arc.util.Time
10 | import arc.util.Tmp
11 | import helium.Helium
12 | import helium.graphics.DrawUtils
13 | import helium.graphics.EdgeLineStripDrawable
14 | import helium.graphics.FillStripDrawable
15 | import helium.graphics.StripDrawable
16 | import mindustry.gen.Tex
17 | import mindustry.graphics.Pal
18 |
19 | object HeAssets {
20 | val lightBlue = Color.valueOf("D3FDFF")
21 |
22 | lateinit var heIcon: Drawable
23 | lateinit var program: Drawable
24 | lateinit var java: Drawable
25 | lateinit var javascript: Drawable
26 |
27 | lateinit var loading: Drawable
28 | lateinit var networkError: Drawable
29 |
30 | lateinit var transparent: Drawable
31 | lateinit var grayUI: Drawable
32 | lateinit var grayUIAlpha: Drawable
33 | lateinit var darkGrayUI: Drawable
34 | lateinit var darkGrayUIAlpha: Drawable
35 | lateinit var padGrayUIAlpha: Drawable
36 | lateinit var slotsBack: Drawable
37 |
38 | lateinit var whiteStrip: StripDrawable
39 | lateinit var whiteEdge: StripDrawable
40 | lateinit var innerLight: StripDrawable
41 | lateinit var outerLight: StripDrawable
42 |
43 | fun load(){
44 | heIcon = Helium.getDrawable("helium")
45 | program = Helium.getDrawable("program")
46 | java = Helium.getDrawable("java")
47 | javascript = Helium.getDrawable("javascript")
48 |
49 | loading = object: BaseDrawable(){
50 | override fun draw(x: Float, y: Float, width: Float, height: Float) {
51 | val r1 = Time.globalTime*2
52 | val r2 = Time.globalTime
53 | val ang = (r1 - r2)%720 - 360f
54 | Lines.stroke(Scl.scl(4f))
55 | DrawUtils.arc(
56 | x + width/2, y + height/2,
57 | width/2.3f, ang, r1
58 | )
59 | }
60 | }
61 | networkError = Helium.getDrawable("network-error")
62 |
63 | slotsBack = Helium.getDrawable("slots-back")
64 |
65 | val white = Tex.whiteui as TextureRegionDrawable
66 | transparent = white.tint(Color.clear)
67 | grayUI = white.tint(Pal.darkerGray)
68 | grayUIAlpha = white.tint(Tmp.c1.set(Pal.darkerGray).a(0.7f))
69 | darkGrayUI = white.tint(Pal.darkestGray)
70 | darkGrayUIAlpha = white.tint(Tmp.c1.set(Pal.darkestGray).a(0.7f))
71 | padGrayUIAlpha = white.tint(Tmp.c1.set(Pal.darkerGray).a(0.7f)).also {
72 | it.leftWidth = 8f
73 | it.rightWidth = 8f
74 | it.topHeight = 8f
75 | it.bottomHeight = 8f
76 | }
77 |
78 | whiteStrip = FillStripDrawable(Color.white)
79 | whiteEdge = EdgeLineStripDrawable(Scl.scl(3f), Color.white)
80 | innerLight = FillStripDrawable(Color.white.cpy().a(0f), Color.white)
81 | outerLight = FillStripDrawable(Color.white, Color.white.cpy().a(0f))
82 | }
83 | }
--------------------------------------------------------------------------------
/src/main/kotlin/helium/ui/HeStyles.kt:
--------------------------------------------------------------------------------
1 | package helium.ui
2 |
3 | import arc.Core
4 | import arc.Events
5 | import arc.graphics.Color
6 | import arc.scene.style.Drawable
7 | import arc.scene.style.NinePatchDrawable
8 | import arc.scene.style.TextureRegionDrawable
9 | import arc.scene.ui.Dialog.DialogStyle
10 | import arc.scene.ui.layout.Scl
11 | import helium.Helium
12 | import helium.graphics.*
13 | import helium.ui.HeAssets.transparent
14 | import helium.ui.elements.roulette.StripButtonStyle
15 | import helium.ui.fragments.entityinfo.displays.HealthBarStyle
16 | import mindustry.game.EventType
17 | import mindustry.graphics.Pal
18 | import mindustry.ui.Fonts
19 | import mindustry.ui.Styles
20 |
21 | object HeStyles {
22 | lateinit var BLUR_BACK: Drawable
23 |
24 | lateinit var blurStrip: StripDrawable
25 |
26 | lateinit var none: StripDrawable
27 | lateinit var black: StripDrawable
28 | lateinit var black9: StripDrawable
29 | lateinit var black8: StripDrawable
30 | lateinit var black7: StripDrawable
31 | lateinit var black6: StripDrawable
32 | lateinit var black5: StripDrawable
33 | lateinit var boundBlack: StripDrawable
34 | lateinit var boundBlack9: StripDrawable
35 | lateinit var boundBlack8: StripDrawable
36 | lateinit var boundBlack7: StripDrawable
37 | lateinit var boundBlack6: StripDrawable
38 | lateinit var boundBlack5: StripDrawable
39 | lateinit var grayPanel: StripDrawable
40 | lateinit var flatOver: StripDrawable
41 | lateinit var edgeFlatOver: StripDrawable
42 | lateinit var flatDown: StripDrawable
43 | lateinit var clearEdge: StripDrawable
44 | lateinit var accent: StripDrawable
45 |
46 | lateinit var transparentBack: DialogStyle
47 |
48 | lateinit var test: HealthBarStyle
49 |
50 | lateinit var clearS: StripButtonStyle
51 | lateinit var toggleClearS: StripButtonStyle
52 | lateinit var boundClearS: StripButtonStyle
53 | lateinit var flatS: StripButtonStyle
54 | lateinit var grayS: StripButtonStyle
55 |
56 | var uiBlur: Blur = Blur(*DEf_B)
57 |
58 | private var drawingCounter = 0
59 | private var lastDialogs = 0
60 |
61 | fun load() {
62 | Events.run(EventType.Trigger.uiDrawBegin) { drawingCounter = 0 }
63 | Events.run(EventType.Trigger.uiDrawEnd) { lastDialogs = drawingCounter }
64 |
65 | BLUR_BACK = object : TextureRegionDrawable(Core.atlas.white()) {
66 | override fun draw(x: Float, y: Float, width: Float, height: Float) {
67 | drawingCounter++
68 | if (drawingCounter == lastDialogs) uiBlur.directDraw {
69 | super.draw(x, y, width, height)
70 | }
71 |
72 | Styles.black5.draw(x, y, width, height)
73 | }
74 |
75 | override fun draw(
76 | x: Float, y: Float, originX: Float, originY: Float,
77 | width: Float, height: Float,
78 | scaleX: Float, scaleY: Float,
79 | rotation: Float,
80 | ) {
81 | drawingCounter++
82 | if (drawingCounter == lastDialogs) uiBlur.directDraw {
83 | super.draw(
84 | x, y, originX, originY,
85 | width, height,
86 | scaleX, scaleY,
87 | rotation
88 | )
89 | }
90 |
91 | Styles.black5.draw(x, y, originX, originY, width, height, scaleX, scaleY, rotation)
92 | }
93 | }
94 |
95 | blurStrip = object: FillStripDrawable(Color.white){
96 | override fun draw(
97 | originX: Float,
98 | originY: Float,
99 | angle: Float,
100 | distance: Float,
101 | angleDelta: Float,
102 | stripWidth: Float,
103 | ) {
104 | drawingCounter++
105 | if (drawingCounter == lastDialogs) uiBlur.directDraw {
106 | super.draw(
107 | originX, originY,
108 | angle, distance,
109 | angleDelta, stripWidth,
110 | )
111 | }
112 | }
113 | }
114 |
115 | none = FillStripDrawable(Color.clear)
116 | black = FillStripDrawable(Color.black)
117 | black9 = FillStripDrawable(Color.black.cpy().a(0.9f))
118 | black8 = FillStripDrawable(Color.black.cpy().a(0.8f))
119 | black7 = FillStripDrawable(Color.black.cpy().a(0.6f))
120 | black6 = FillStripDrawable(Color.black.cpy().a(0.5f))
121 | black5 = FillStripDrawable(Color.black.cpy().a(0.3f))
122 | boundBlack = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black)
123 | boundBlack9 = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black.cpy().a(0.9f))
124 | boundBlack8 = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black.cpy().a(0.8f))
125 | boundBlack7 = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black.cpy().a(0.6f))
126 | boundBlack6 = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black.cpy().a(0.5f))
127 | boundBlack5 = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.black.cpy().a(0.3f))
128 | grayPanel = FillStripDrawable(Pal.darkestGray)
129 | flatOver = FillStripDrawable(Color.valueOf("454545").a(0.6f))
130 | flatDown = EdgeLineStripDrawable(Scl.scl(3f), Pal.accent)
131 | edgeFlatOver = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray, Color.valueOf("454545"))
132 | clearEdge = EdgeLineStripDrawable(Scl.scl(3f), Pal.darkestGray)
133 | accent = FillStripDrawable(Pal.accent)
134 |
135 | transparentBack = object : DialogStyle() {
136 | init {
137 | stageBackground = transparent
138 | titleFont = Fonts.outline
139 | background = transparent
140 | titleFontColor = Pal.accent
141 | }
142 | }
143 |
144 | test = HealthBarStyle(
145 | background = ScaledNinePatchClipDrawable(Helium.getDrawable("background") as NinePatchDrawable),
146 | backgroundColor = Color.white.cpy().a(0.6f),
147 | healthBar = ScaledNinePatchClipDrawable(Helium.getDrawable("healthbar") as NinePatchDrawable),
148 | healthPadLeft = 6,
149 | healthPadRight = 6,
150 | shieldBar = ScaledNinePatchClipDrawable(Helium.getDrawable("shieldbar") as NinePatchDrawable),
151 | shieldPadLeft = 5,
152 | shieldPadRight = 5,
153 | font = Fonts.outline,
154 | texOffX = 15,
155 | texOffY = 7,
156 | shieldsOffX = 15,
157 | shieldsOffY = 7
158 | )
159 |
160 | flatS = StripButtonStyle(
161 | over = flatOver,
162 | down = flatOver,
163 | up = black,
164 | )
165 | grayS = StripButtonStyle(
166 | over = flatOver,
167 | down = flatOver,
168 | up = grayPanel,
169 | )
170 | clearS = StripButtonStyle(
171 | down = flatDown,
172 | up = none,
173 | over = flatOver,
174 | )
175 | toggleClearS = StripButtonStyle(
176 | down = flatDown,
177 | up = none,
178 | over = flatOver,
179 | checked = flatDown,
180 | checkedOver = EdgeLineStripDrawable(Scl.scl(3f), Pal.accent, Color.valueOf("454545").a(0.6f)),
181 | )
182 | boundClearS = StripButtonStyle(
183 | down = flatDown,
184 | up = clearEdge,
185 | over = edgeFlatOver,
186 | )
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/kotlin/helium/ui/UIUtils.kt:
--------------------------------------------------------------------------------
1 | package helium.ui
2 |
3 | import arc.Core
4 | import arc.func.Boolp
5 | import arc.func.Cons
6 | import arc.func.Cons2
7 | import arc.func.Prov
8 | import arc.graphics.Color
9 | import arc.scene.style.Drawable
10 | import arc.scene.ui.Dialog
11 | import arc.scene.ui.Image
12 | import arc.scene.ui.layout.Cell
13 | import arc.scene.ui.layout.Table
14 | import arc.util.Align
15 | import arc.util.Strings
16 | import helium.invoke
17 | import mindustry.gen.Icon
18 | import mindustry.graphics.Pal
19 | import mindustry.ui.Styles
20 |
21 | object UIUtils {
22 | val cancelBut = ButtonEntry(Core.bundle["cancel"], Icon.cancel, clicked = { it.hide() })
23 | val closeBut = ButtonEntry(Core.bundle["misc.close"], Icon.cancel, clicked = { it.hide() })
24 |
25 | fun showException(e: Throwable, message: String? = null) = showPane(
26 | Core.bundle["infos.exception"],
27 | ButtonEntry(Core.bundle["confirm"], Icon.ok) { it.hide() },
28 | titleColor = Color.crimson,
29 | ){ t ->
30 | message?.also {
31 | t.add(it)
32 | t.row()
33 | }
34 | t.row()
35 | t.pane(Styles.smallPane) { pane ->
36 | pane.add(Strings.neatError(e)).color(Color.lightGray).left().fill()
37 | }.fill().margin(14f).maxHeight(800f)
38 | }
39 |
40 | fun showError(message: String) = showPane(
41 | Core.bundle["infos.error"],
42 | ButtonEntry(Core.bundle["confirm"], Icon.ok) { it.hide() },
43 | titleColor = Color.crimson,
44 | ){ t ->
45 | t.add(message)
46 | t.row()
47 | }
48 |
49 | fun showInput(
50 | title: String?,
51 | message: String,
52 | area: Boolean = false,
53 | buildContent: Cons? = null,
54 | callback: Cons2