Skip to content

Commit

Permalink
Add rust to fix curses CJK offsets
Browse files Browse the repository at this point in the history
  • Loading branch information
ChillerDragon committed Apr 22, 2023
1 parent 9d29b96 commit d29a641
Show file tree
Hide file tree
Showing 21 changed files with 406 additions and 85 deletions.
18 changes: 13 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,9 @@ set(RUST_SRC
Cargo.lock
)
set(RUST_TARGETS engine_shared)

include("cmake/chillerbot/chillerbot_rust.cmake")

if(NOT CMAKE_OSX_ARCHITECTURES)
set(RUST_OUTPUTS)
foreach(rust_target ${RUST_TARGETS})
Expand Down Expand Up @@ -1884,8 +1887,6 @@ set_src(BASE GLOB_RECURSE src/base
bezier.h
chillerbot/curses_colors.cpp
chillerbot/curses_colors.h
chillerbot/pad_utf8.cpp
chillerbot/pad_utf8.h
chillerbot/terminalui_logger.h
color.h
curses.h
Expand Down Expand Up @@ -2247,6 +2248,8 @@ if(CLIENT)
components/chillerbot/terminalui/history.cpp
components/chillerbot/terminalui/maplayers.cpp
components/chillerbot/terminalui/menus.cpp
components/chillerbot/terminalui/pad_utf8.cpp
components/chillerbot/terminalui/pad_utf8.h
components/chillerbot/terminalui/scoreboard.cpp
components/chillerbot/terminalui/terminalui.cpp
components/chillerbot/terminalui/terminalui.h
Expand Down Expand Up @@ -2403,6 +2406,7 @@ if(CLIENT)

${TARGET_STEAMAPI}
rust_engine_shared
rust_chillerbot_rs

${PLATFORM_CLIENT_LIBS}
${LIBS}
Expand Down Expand Up @@ -2441,6 +2445,7 @@ if(CLIENT)
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
$<TARGET_OBJECTS:rust-bridge-shared>
$<TARGET_OBJECTS:rust-bridge-chillerbot>
)
else()
add_executable(game-client WIN32
Expand All @@ -2452,6 +2457,7 @@ if(CLIENT)
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
$<TARGET_OBJECTS:rust-bridge-shared>
$<TARGET_OBJECTS:rust-bridge-chillerbot>
)
endif()
set_property(TARGET game-client
Expand Down Expand Up @@ -2631,6 +2637,7 @@ if(SERVER)
${MYSQL_LIBRARIES}
${TARGET_ANTIBOT}
rust_engine_shared
rust_chillerbot_rs

${LIBS}
)
Expand All @@ -2643,6 +2650,7 @@ if(SERVER)
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
$<TARGET_OBJECTS:rust-bridge-shared>
$<TARGET_OBJECTS:rust-bridge-chillerbot>
)
set_property(TARGET game-server
PROPERTY OUTPUT_NAME ${SERVER_EXECUTABLE}
Expand Down Expand Up @@ -2880,6 +2888,7 @@ add_library(rust_test STATIC EXCLUDE_FROM_ALL
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
$<TARGET_OBJECTS:rust-bridge-shared>
$<TARGET_OBJECTS:rust-bridge-chillerbot>
${DEPS}
)

Expand Down Expand Up @@ -3406,9 +3415,6 @@ foreach(target ${TARGETS_OWN})
if(HEADLESS_CLIENT)
target_compile_definitions(${target} PRIVATE CONF_HEADLESS_CLIENT)
endif()
if(CURSES_CLIENT)
target_compile_definitions(${target} PRIVATE CONF_CURSES_CLIENT)
endif()
if(MYSQL)
target_compile_definitions(${target} PRIVATE CONF_MYSQL)
target_include_directories(${target} SYSTEM PRIVATE ${MYSQL_INCLUDE_DIRS})
Expand Down Expand Up @@ -3439,6 +3445,8 @@ foreach(target ${TARGETS_OWN})
endif()
endforeach()

include("cmake/chillerbot/targets.cmake")

foreach(target ${TARGETS_DEP})
if(MSVC)
target_compile_options(${target} PRIVATE /W0)
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"src/base",
"src/chillerbot-rs",
"src/engine",
"src/engine/shared",
"src/rust-bridge/test",
Expand Down
51 changes: 51 additions & 0 deletions cmake/chillerbot/chillerbot_rust.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
message(STATUS "~~~~~~ chillerbot rust module ~~~~~~")

set_glob(RUST_CHILLERBOT_RS GLOB_RECURSE "rs;toml;h;cpp" src/chillerbot-rs
Cargo.toml
build.rs
lib.rs
unicode.rs
)

set_src(RUST_BRIDGE_CHILLERBOT GLOB_RECURSE src/rust-bridge-chillerbot
unicode.cpp
unicode.h
)

add_library(rust-bridge-chillerbot EXCLUDE_FROM_ALL OBJECT ${RUST_BRIDGE_CHILLERBOT})
list(APPEND TARGETS_OWN rust-bridge-chillerbot)

#####################################################################
# overwrite variables if current content matches expected
#
# could probably also use list(APPEND ..) but lets me strict for now
# to be alerted if somehing changes before weird build errors occur

if(RUST_TARGETS STREQUAL "engine_shared")
message(STATUS " * patching RUST_TARGETS ...")
set(RUST_TARGETS engine_shared chillerbot_rs)
else()
message(SEND_ERROR " failed to patch RUST_TARGETS unexpected content '${RUST_TARGETS}'")
endif()

set(CHILLERBOT_EXPECTED_RUST_SRC
${RUST_BASE}
${RUST_ENGINE_INTERFACE}
${RUST_ENGINE_SHARED}
Cargo.toml
Cargo.lock
)

if(RUST_SRC STREQUAL CHILLERBOT_EXPECTED_RUST_SRC)
message(STATUS " * patching RUST_SRC ...")
set(RUST_SRC
${RUST_BASE}
${RUST_ENGINE_INTERFACE}
${RUST_ENGINE_SHARED}
${RUST_CHILLERBOT_RS}
Cargo.toml
Cargo.lock
)
else()
message(SEND_ERROR " failed to patch RUST_SRC unexpected content '${RUST_SRC}'")
endif()
11 changes: 11 additions & 0 deletions cmake/chillerbot/targets.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
foreach(target ${TARGETS_OWN})
if((CMAKE_VERSION VERSION_GREATER 3.1 OR CMAKE_VERSION VERSION_EQUAL 3.1))
set_property(TARGET ${target} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS OFF)
endif()
target_include_directories(${target} PRIVATE src/rust-bridge-chillerbot)
if(CURSES_CLIENT)
target_compile_definitions(${target} PRIVATE CONF_CURSES_CLIENT)
endif()
endforeach()
18 changes: 0 additions & 18 deletions src/base/chillerbot/pad_utf8.cpp

This file was deleted.

20 changes: 20 additions & 0 deletions src/chillerbot-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "ddnet-chillerbot-rs"
version = "0.0.1"
edition = "2018"
publish = false
license = "Zlib"

[lib]
crate-type = ["rlib", "staticlib"]
path = "lib.rs"

[dependencies]
ddnet-base = { path = "../base" }
ddnet-engine = { path = "../engine" }

cxx = "1.0"
unicode-width = "0.1.10"

[dev-dependencies]
ddnet-test = { path = "../rust-bridge/test", features = ["link-test-libraries"] }
18 changes: 18 additions & 0 deletions src/chillerbot-rs/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

fn main() {
let mut out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));
out.push("rustc-version");
let rustc = env::var_os("RUSTC").expect("RUSTC");
let rustc_output = Command::new(rustc)
.arg("--version")
.output()
.expect("rustc --version");
if !rustc_output.status.success() {
panic!("rustc --version: exit status {}", rustc_output.status);
}
fs::write(&out, rustc_output.stdout).expect("file write");
}
19 changes: 19 additions & 0 deletions src/chillerbot-rs/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! chillerbots's engine interfaces, Rust part.
//!
//! DDNet's code base is separated into three major parts, `base`, `engine` and
//! `game`.
//!
//! The engine consists of game-independent code such as display setup,
//! low-level network protocol, low-level map format, etc.
//!
//! This crate in particular corresponds to the `src/engine/shared` directory
//! that contains code shared between client, server and other components.
#![warn(missing_docs)]

#[cfg(test)]
extern crate ddnet_test;

mod unicode;

pub use unicode::*;
45 changes: 45 additions & 0 deletions src/chillerbot-rs/unicode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::ffi::CStr;
use std::os::raw::c_char;

extern crate unicode_width;

use unicode_width::UnicodeWidthStr;

#[cxx::bridge]
mod ffi {
extern "C++" {
include!("base/rust.h");
}
extern "Rust" {
unsafe fn str_width_unicode(text: *const c_char) -> i32;
}
}

/// Count the width in columns of a given string.
///
/// So one can get the display length of any string
/// in a fixed width font scenario.
///
/// Simply calling str_length() does not work if there is unicode
/// since some unicode characters can be multiple bytes
/// and even counting unicode characters does not work
/// because CJK (chines/japan/korean) characters
/// have a concept of full and half width
/// meaning one single unicode character can span two columns
///
/// For example this character spans two columns
/// ```text
/// +--+
/// |困|
/// |12|
/// +--+
/// ```
#[allow(non_snake_case)]
pub fn str_width_unicode(text: *const c_char) -> i32 {
let slice = unsafe { CStr::from_ptr(text) };
let slice = slice.to_str().unwrap_or_default();
// .width_cjk().try_into().unwrap();
// returns width 2 for the letter é
let width = UnicodeWidthStr::width(slice) as i32;
return width;
}
12 changes: 8 additions & 4 deletions src/game/client/components/chillerbot/terminalui/menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include <csignal>

#include <base/chillerbot/pad_utf8.h>
#include "pad_utf8.h"

#include "terminalui.h"

Expand Down Expand Up @@ -143,21 +143,25 @@ void CTerminalUI::RenderServerList()
}

str_pad_right_utf8(aName, sizeof(aName), 60);
str_pad_right_utf8(aMap, sizeof(aMap), 20);
str_pad_right_utf8(aPlayers, sizeof(aPlayers), 16);
str_format(aBuf, sizeof(aBuf),
"%s | %-20s | %-16s",
"%s | %s | %s",
aName,
aMap,
aPlayers);
aBuf[width - 1] = '\0'; // ensure no line wrapping
if(m_SelectedServer == i)
{
wattron(g_LogWindow.m_pCursesWin, A_BOLD);
str_format(aLine, sizeof(aLine), "<%-*s>", width - 2, aBuf);
str_pad_right_utf8(aBuf, sizeof(aBuf), width - 2);
str_format(aLine, sizeof(aLine), "<%s>", aBuf);
}
else
{
wattroff(g_LogWindow.m_pCursesWin, A_BOLD);
str_format(aLine, sizeof(aLine), "|%-*s|", width - 2, aBuf);
str_pad_right_utf8(aBuf, sizeof(aBuf), width - 2);
str_format(aLine, sizeof(aLine), "|%s|", aBuf);
}
mvwprintw(g_LogWindow.m_pCursesWin, offY + k, offX, "%s", aLine);
}
Expand Down
23 changes: 23 additions & 0 deletions src/game/client/components/chillerbot/terminalui/pad_utf8.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#if defined(CONF_CURSES_CLIENT)

#include "pad_utf8.h"
#include <base/system.h>

#include <rust-bridge-chillerbot/unicode.h>

void str_pad_right_utf8(char *pStr, int size, int pad_len)
{
char aBuf[2048];
str_copy(aBuf, pStr, sizeof(aBuf));
int full_width_length = str_width_unicode(pStr);
int c_len = str_length(pStr);
int pad_len_utf8_rust = pad_len - (full_width_length - c_len);

str_format(pStr, size, "%-*s", pad_len_utf8_rust, aBuf);
// dbg_msg(
// "pad",
// "pad_len=%d pad_len_utf8_rust=%d res='%s'",
// pad_len, pad_len_utf8_rust, pStr);
}

#endif
Loading

0 comments on commit d29a641

Please sign in to comment.