Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
permissions:
actions: read
contents: read
pull-requests: write
security-events: write

steps:
Expand All @@ -33,8 +34,30 @@ jobs:
run: ./gradlew build

- name: Lint
id: lint
continue-on-error: true
run: ./gradlew lint

- name: Count lint violations
id: count_violations
if: steps.lint.outcome == 'failure'
run: |
./gradlew lint || echo "::warning::Checkstyle found violations. See the checkstyle-report artifact for details."
count=$(grep -r '<error ' build/reports/checkstyle/ | wc -l)
echo "count=$count" >> $GITHUB_OUTPUT

- name: Comment on PR if lint failed
if: steps.lint.outcome == 'failure' && github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const count = ${{ steps.count_violations.outputs.count }};
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `:warning: **Checkstyle found ${count} style violation${count === 1 ? '' : 's'}.** Download the **checkstyle-report** artifact from the [Actions run](${runUrl}) for details.`
})

- name: Determine artifact name
id: find_artifact
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ steam_app_id.txt
/Tests
/src/main/resources/hash.txt
libs.tar.gz
chars
.claude
.antigravitycli
69 changes: 69 additions & 0 deletions slicr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from PIL import Image
import svgwrite
import fontforge

SCALER = 24
OFF = 10

chars = (" !\"#$%&'()*+,-./" +
"0123456789:;<=>?" +
"@ABCDEFGHIJKLMNO" +
"PQRSTUVWXYZ[\\]^_" +
"'abcdefghijklmno" +
"pqrstuvwxyz{|}~`" +
"âăîşţàçæèéêëïôœù" +
"úûüÿáíóñ¡¿äöå")

def save_char(char_id, cell_width, cell_height, char_img):
dwg = svgwrite.Drawing(f"chars/{chars[char_id]}.svg", size=(f"{cell_width*SCALER}px", f"{(cell_height-(2*OFF))*SCALER}px"), profile='tiny')
for y in range(cell_height):
for x in range(cell_width):
r, g, b, a = char_img.getpixel((x, y))
if a > 0:
hex_color = f'#{r:02x}{g:02x}{b:02x}'
dwg.add(dwg.rect((x*SCALER, (y-OFF)*SCALER), (SCALER, SCALER), fill=hex_color))

dwg.save()

def slice_image(image_path, cell_width, cell_height):
"""
Slices a grid image into individual character PNGs.
"""
img = Image.open(image_path)
width, height = img.size

char_id = 0
for y in range(0, height, cell_height):
for x in range(0, width, cell_width):
box = (x, y, x + cell_width, y + cell_height)
char_img = img.crop(box)
if (char_id < len(chars)):
save_char(char_id, cell_width, cell_height, char_img)
char_id += 1

def fontify():
slice_image("src/main/resources/fonts/default/font.png", 32, 64)
font = fontforge.font()
font.fontname = "Bullet"
font.fullname = "Bullet Sans"
font.familyname = "Bullet"
font.encoding = "UnicodeBMP"
font.copyright = "Copyright (c) 2025 Matei Budiu, Parth Iyer"
for char in chars:
glyph = font.createChar(ord(char))
try:
if char == ' ':
glyph.width = 15 * SCALER
else:
glyph.importOutlines(f"chars/{char}.svg")
xmin, ymin, xmax, ymax = glyph.boundingBox()
glyph.width = int(xmax - xmin + 5*SCALER/2)
glyph.left_side_bearing = int(5*SCALER/2)

except Exception as e:
print(f"Error processing {char}: {e}")

font.autoWidth(0)
font.generate("src/main/resources/fonts/default/Bullet.ttf")

fontify()
43 changes: 5 additions & 38 deletions src/main/java/lwjglwindow/LWJGLWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import basewindow.*;
import basewindow.transformation.Matrix4;
import basewindow.transformation.Transformation;
import tanks.Game;

import de.matthiasmann.twl.utils.PNGDecoder;
import de.matthiasmann.twl.utils.PNGDecoder.Format;
Expand Down Expand Up @@ -129,42 +128,10 @@ public void run()

protected void init()
{
this.fontRenderer = new FontRenderer(this, "/fonts/default/font.png");

// Load zh cn font
try
{
int count = 1;
while (true)
{
try (InputStream zhCnFontInputStream = LWJGLWindow.class.getClassLoader().getResourceAsStream("fonts/zh_cn/font_zh_cn_" + count + ".png");
InputStream zhCnTxtInputStream = LWJGLWindow.class.getClassLoader().getResourceAsStream("fonts/zh_cn/font_zh_cn_" + count + ".txt"))
{
if (zhCnFontInputStream == null) break;
if (zhCnTxtInputStream == null)
{
System.err.println("Failed to load zh cn font " + count);
continue;
}
Scanner scanner = new Scanner(Objects.requireNonNull(zhCnTxtInputStream), StandardCharsets.UTF_8.name());
StringBuilder sb = new StringBuilder();
while (scanner.hasNextLine())
{
sb.append(scanner.nextLine());
}
String chinese_chars = sb.toString();
int[] chinese_chars_sizes = new int[chinese_chars.length()];
Arrays.fill(chinese_chars_sizes, 8);
this.fontRenderer.addFont("/fonts/zh_cn/font_zh_cn_" + count + ".png", chinese_chars, chinese_chars_sizes);
count++;
}
}
}
catch (IOException e)
{
e.printStackTrace(Game.logger);
e.printStackTrace();
}
TruetypeFontRenderer ttf = new TruetypeFontRenderer(this, "/fonts/default/Bullet.ttf", 128, true, 1.4, 0.3);
ttf.addFontsFromDirectory(System.getProperty("user.home") + "/.tanks/fonts", 128, false, 1.4, 0.3);
ttf.addSystemFonts(128, false, 1.4, 0.3);
this.fontRenderer = ttf;

GLFWErrorCallback.createPrint(System.err).set();

Expand Down Expand Up @@ -1410,4 +1377,4 @@ public void setForceModelGlow(boolean glow)
{
this.forceModelGlow = glow;
}
}
}
Loading
Loading